diff --git a/.vscode/settings.json b/.vscode/settings.json index cfe45b8bc..272443176 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -183,4 +183,8 @@ "./kernel/Cargo.toml", "./kernel/src/libs/ida/Cargo.toml" ], + "rust-analyzer.check.overrideCommand": [ + "make", + "check" + ], } \ No newline at end of file diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 82dd7b6ab..faf47f4cf 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -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" } diff --git a/kernel/Makefile b/kernel/Makefile index edfb8a475..acf5e2159 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -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 diff --git a/kernel/build.rs b/kernel/build.rs index 5d80d0d4c..da452751b 100644 --- a/kernel/build.rs +++ b/kernel/build.rs @@ -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) { + 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) { + 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 { + let mut queue: Vec = 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; } } diff --git a/kernel/src/Makefile b/kernel/src/Makefile index 900d5ec70..ec31f2ac4 100644 --- a/kernel/src/Makefile +++ b/kernel/src/Makefile @@ -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 diff --git a/kernel/src/arch/Makefile b/kernel/src/arch/Makefile index e2e8a1649..e4b68c0fa 100644 --- a/kernel/src/arch/Makefile +++ b/kernel/src/arch/Makefile @@ -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 diff --git a/kernel/src/arch/x86_64/Makefile b/kernel/src/arch/x86_64/Makefile index 9e6ce0661..e11e5a78a 100644 --- a/kernel/src/arch/x86_64/Makefile +++ b/kernel/src/arch/x86_64/Makefile @@ -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) diff --git a/kernel/src/arch/x86_64/asm/Makefile b/kernel/src/arch/x86_64/asm/Makefile index 38af6da5e..6fa03e03d 100644 --- a/kernel/src/arch/x86_64/asm/Makefile +++ b/kernel/src/arch/x86_64/asm/Makefile @@ -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) diff --git a/kernel/src/arch/x86_64/driver/apic/apic.c b/kernel/src/arch/x86_64/driver/apic/apic.c new file mode 100644 index 000000000..541878c8b --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/apic.c @@ -0,0 +1,228 @@ +#include "apic.h" +#include "apic_timer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 \ No newline at end of file diff --git a/kernel/src/driver/interrupt/apic/apic.h b/kernel/src/arch/x86_64/driver/apic/apic.h similarity index 79% rename from kernel/src/driver/interrupt/apic/apic.h rename to kernel/src/arch/x86_64/driver/apic/apic.h index 08fb706ea..4eea5c966 100644 --- a/kernel/src/driver/interrupt/apic/apic.h +++ b/kernel/src/arch/x86_64/driver/apic/apic.h @@ -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 \ No newline at end of file diff --git a/kernel/src/driver/interrupt/apic/apic_timer.c b/kernel/src/arch/x86_64/driver/apic/apic_timer.c similarity index 52% rename from kernel/src/driver/interrupt/apic/apic_timer.c rename to kernel/src/arch/x86_64/driver/apic/apic_timer.c index 99288f73a..58190bf81 100644 --- a/kernel/src/driver/interrupt/apic/apic_timer.c +++ b/kernel/src/arch/x86_64/driver/apic/apic_timer.c @@ -4,15 +4,15 @@ #include #include -// #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); -} \ No newline at end of file +} diff --git a/kernel/src/arch/x86_64/driver/apic/apic_timer.h b/kernel/src/arch/x86_64/driver/apic/apic_timer.h new file mode 100644 index 000000000..5e8bcd90d --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/apic_timer.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "apic.h" + +#define APIC_TIMER_IRQ_NUM 151 + +/** + * @brief 初始化local APIC定时器 + * + */ +void apic_timer_init(); + +void apic_timer_ap_core_init(); diff --git a/kernel/src/arch/x86_64/driver/apic/apic_timer.rs b/kernel/src/arch/x86_64/driver/apic/apic_timer.rs new file mode 100644 index 000000000..7d00eb9ba --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/apic_timer.rs @@ -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; 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 for LocalApicTimerMode { + type Error = SystemError; + + fn try_from(value: u8) -> Result { + 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, + ) + }; + } + } +} diff --git a/kernel/src/arch/x86_64/driver/apic/c_adapter.rs b/kernel/src/arch/x86_64/driver/apic/c_adapter.rs new file mode 100644 index 000000000..a789a9b29 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/c_adapter.rs @@ -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()); +} diff --git a/kernel/src/arch/x86_64/driver/apic/ioapic.rs b/kernel/src/arch/x86_64/driver/apic/ioapic.rs new file mode 100644 index 000000000..eae634f4b --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/ioapic.rs @@ -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> = None; + +#[allow(non_snake_case)] +fn IOAPIC() -> &'static SpinLock { + 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 = None; + INIT_STATE.call_once(|| { + kinfo!("Initializing ioapic..."); + + // get ioapic base from acpi + + let madt = acpi_manager() + .tables() + .unwrap() + .find_table::() + .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, + } + + 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); +} diff --git a/kernel/src/arch/x86_64/driver/apic/mod.rs b/kernel/src/arch/x86_64/driver/apic/mod.rs new file mode 100644 index 000000000..dd5b3cb82 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/mod.rs @@ -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 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 { + // 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 { + 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 { + 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 { + 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 for DeliveryMode { + type Error = SystemError; + + fn try_from(value: u8) -> Result { + 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); + }); + } + } +} diff --git a/kernel/src/arch/x86_64/driver/apic/x2apic.rs b/kernel/src/arch/x86_64/driver/apic/x2apic.rs new file mode 100644 index 000000000..3f24aea48 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/x2apic.rs @@ -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) }; + } +} diff --git a/kernel/src/arch/x86_64/driver/apic/xapic.rs b/kernel/src/arch/x86_64/driver/apic/xapic.rs new file mode 100644 index 000000000..4ec2b3a15 --- /dev/null +++ b/kernel/src/arch/x86_64/driver/apic/xapic.rs @@ -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>; PerCpu::MAX_CPU_NUM] = + [const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM]; + +#[inline(always)] +pub(super) fn current_xapic_instance() -> &'static RefCell> { + 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 for XApicOffset { + fn into(self) -> u32 { + self as u32 + } +} + +impl From 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(); + } + } + } +} diff --git a/kernel/src/arch/x86_64/driver/hpet.c b/kernel/src/arch/x86_64/driver/hpet.c index 9714eb23b..8eeb6407b 100644 --- a/kernel/src/arch/x86_64/driver/hpet.c +++ b/kernel/src/arch/x86_64/driver/hpet.c @@ -1,6 +1,6 @@ #include #include -#include +#include extern void rs_handle_hpet_irq(uint32_t timer_num); diff --git a/kernel/src/arch/x86_64/driver/mod.rs b/kernel/src/arch/x86_64/driver/mod.rs index 47ade1d22..fc9ed1533 100644 --- a/kernel/src/arch/x86_64/driver/mod.rs +++ b/kernel/src/arch/x86_64/driver/mod.rs @@ -1,3 +1,4 @@ +pub mod apic; mod c_adapter; pub mod hpet; pub mod tsc; diff --git a/kernel/src/arch/x86_64/interrupt/c_adapter.rs b/kernel/src/arch/x86_64/interrupt/c_adapter.rs new file mode 100644 index 000000000..87b0e7b5e --- /dev/null +++ b/kernel/src/arch/x86_64/interrupt/c_adapter.rs @@ -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()); +} diff --git a/kernel/src/arch/x86_64/interrupt/ipi.rs b/kernel/src/arch/x86_64/interrupt/ipi.rs index d32b5c90e..d7536b8e3 100644 --- a/kernel/src/arch/x86_64/interrupt/ipi.rs +++ b/kernel/src/arch/x86_64/interrupt/ipi.rs @@ -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 for ArchIpiTarget { @@ -41,7 +45,23 @@ impl From 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 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 for ArchIpiTarget { @@ -68,21 +97,6 @@ impl Into for ArchIpiTarget { } } -impl Into 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(()); } diff --git a/kernel/src/arch/x86_64/interrupt/mod.rs b/kernel/src/arch/x86_64/interrupt/mod.rs index f27941b4f..3864f5c89 100644 --- a/kernel/src/arch/x86_64/interrupt/mod.rs +++ b/kernel/src/arch/x86_64/interrupt/mod.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +mod c_adapter; pub mod ipi; use core::{ diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index df946b408..aebfc4898 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -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); + if unlikely(siginfo.is_none()) { + return; + } + + let siginfo_read_guard = siginfo.unwrap(); + // 检查sigpending是否为0 - if siginfo - .map(|s| s.sig_pending().signal().bits() == 0) - .unwrap_or(true) - || !frame.from_user() - { - // 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回 - CurrentIrqArch::interrupt_enable(); + 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; 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 = 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::()); // kdebug!("frame=0x{:016x}", frame as usize); // 要求这个frame的地址位于用户空间,因此进行校验 - let r = UserBufferWriter::new(frame, size_of::(), true); + let r: Result, SystemError> = + UserBufferWriter::new(frame, size_of::(), true); if r.is_err() { // 如果地址区域位于内核空间,则直接报错 // todo: 生成一个sigsegv diff --git a/kernel/src/arch/x86_64/x86_64_ipi.c b/kernel/src/arch/x86_64/x86_64_ipi.c index 411891f0e..f73f929cc 100644 --- a/kernel/src/arch/x86_64/x86_64_ipi.c +++ b/kernel/src/arch/x86_64/x86_64_ipi.c @@ -1,39 +1,5 @@ #include "x86_64_ipi.h" -#include - -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 int ipi_regiserIPI(uint64_t irq_num, void *arg, void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs), @@ -46,4 +12,4 @@ int ipi_regiserIPI(uint64_t irq_num, void *arg, p->flags = 0; p->handler = handler; return 0; -} \ No newline at end of file +} \ No newline at end of file diff --git a/kernel/src/arch/x86_64/x86_64_ipi.h b/kernel/src/arch/x86_64/x86_64_ipi.h index 060ad556c..f3a499f54 100644 --- a/kernel/src/arch/x86_64/x86_64_ipi.h +++ b/kernel/src/arch/x86_64/x86_64_ipi.h @@ -12,22 +12,7 @@ #pragma once #include -#include - -/** - * @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 /** * @brief ipi中断处理注册函数 diff --git a/kernel/src/common/Makefile b/kernel/src/common/Makefile index 1f54d8287..a7ce01f4b 100644 --- a/kernel/src/common/Makefile +++ b/kernel/src/common/Makefile @@ -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) diff --git a/kernel/src/driver/Makefile b/kernel/src/driver/Makefile index c4dc4ce06..f19e7f28a 100644 --- a/kernel/src/driver/Makefile +++ b/kernel/src/driver/Makefile @@ -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) diff --git a/kernel/src/driver/hid/Makefile b/kernel/src/driver/hid/Makefile index 72f3f42e8..3bd0a2a9b 100644 --- a/kernel/src/driver/hid/Makefile +++ b/kernel/src/driver/hid/Makefile @@ -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 diff --git a/kernel/src/driver/interrupt/8259A/8259A.c b/kernel/src/driver/interrupt/8259A/8259A.c deleted file mode 100644 index 1879d2470..000000000 --- a/kernel/src/driver/interrupt/8259A/8259A.c +++ /dev/null @@ -1,66 +0,0 @@ -#include "8259A.h" -#include -#include -#include - -// 导出定义在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); -} \ No newline at end of file diff --git a/kernel/src/driver/interrupt/8259A/8259A.h b/kernel/src/driver/interrupt/8259A/8259A.h deleted file mode 100644 index 36364ec34..000000000 --- a/kernel/src/driver/interrupt/8259A/8259A.h +++ /dev/null @@ -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 -#include - -#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); - - - diff --git a/kernel/src/driver/interrupt/Makefile b/kernel/src/driver/interrupt/Makefile deleted file mode 100644 index e886b99a6..000000000 --- a/kernel/src/driver/interrupt/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/kernel/src/driver/interrupt/apic/apic.c b/kernel/src/driver/interrupt/apic/apic.c deleted file mode 100644 index 337d331dc..000000000 --- a/kernel/src/driver/interrupt/apic/apic.c +++ /dev/null @@ -1,741 +0,0 @@ -#include "apic.h" -#include "apic_timer.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 \ No newline at end of file diff --git a/kernel/src/driver/interrupt/apic/apic2rust.h b/kernel/src/driver/interrupt/apic/apic2rust.h deleted file mode 100644 index 320c9fbfe..000000000 --- a/kernel/src/driver/interrupt/apic/apic2rust.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -extern uint64_t ioapic_get_base_paddr(); \ No newline at end of file diff --git a/kernel/src/driver/interrupt/apic/apic_timer.h b/kernel/src/driver/interrupt/apic/apic_timer.h deleted file mode 100644 index ec97b86dc..000000000 --- a/kernel/src/driver/interrupt/apic/apic_timer.h +++ /dev/null @@ -1,110 +0,0 @@ -#pragma once - -#include -#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 \ No newline at end of file diff --git a/kernel/src/driver/keyboard/ps2_keyboard.c b/kernel/src/driver/keyboard/ps2_keyboard.c index 4a559d719..9c32f5599 100644 --- a/kernel/src/driver/keyboard/ps2_keyboard.c +++ b/kernel/src/driver/keyboard/ps2_keyboard.c @@ -1,5 +1,5 @@ #include "ps2_keyboard.h" -#include +#include #include #include #include diff --git a/kernel/src/driver/mouse/ps2_mouse.c b/kernel/src/driver/mouse/ps2_mouse.c index 397e1efdb..a01676467 100644 --- a/kernel/src/driver/mouse/ps2_mouse.c +++ b/kernel/src/driver/mouse/ps2_mouse.c @@ -1,5 +1,5 @@ #include "ps2_mouse.h" -#include +#include #include #include #include @@ -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.destination.physical.reserved1 = 0; - ps2_mouse_entry.destination.physical.reserved2 = 0; - ps2_mouse_entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器 + // 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处理器 // 注册中断处理程序 irq_register(PS2_MOUSE_INTR_VECTOR, &ps2_mouse_entry, &ps2_mouse_handler, (ul)ps2_mouse_buf_ptr, &ps2_mouse_intr_controller, "ps/2 mouse"); diff --git a/kernel/src/exception/entry.S b/kernel/src/exception/entry.S index 734e104db..ce67d50c1 100644 --- a/kernel/src/exception/entry.S +++ b/kernel/src/exception/entry.S @@ -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 diff --git a/kernel/src/exception/irq.c b/kernel/src/exception/irq.c index 24c9407b0..bed67d9c9 100644 --- a/kernel/src/exception/irq.c +++ b/kernel/src/exception/irq.c @@ -5,7 +5,7 @@ #if _INTR_8259A_ #include #else -#include +#include #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, diff --git a/kernel/src/exception/irq.h b/kernel/src/exception/irq.h index 364fd19bb..04b9d5ea7 100644 --- a/kernel/src/exception/irq.h +++ b/kernel/src/exception/irq.h @@ -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 { // 使能中断操作接口 diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 3385f43c5..78d9c822c 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -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)?; diff --git a/kernel/src/include/bindings/wrapper.h b/kernel/src/include/bindings/wrapper.h index 605e373cc..f6712de97 100644 --- a/kernel/src/include/bindings/wrapper.h +++ b/kernel/src/include/bindings/wrapper.h @@ -43,4 +43,4 @@ #include #include #include -#include +#include diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 5c1f7fbca..a7e13ff6e 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -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)] diff --git a/kernel/src/libs/Makefile b/kernel/src/libs/Makefile index 90cda8f17..ddcc98b7f 100644 --- a/kernel/src/libs/Makefile +++ b/kernel/src/libs/Makefile @@ -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 diff --git a/kernel/src/libs/lock_free_flags.rs b/kernel/src/libs/lock_free_flags.rs new file mode 100644 index 000000000..41f8767cd --- /dev/null +++ b/kernel/src/libs/lock_free_flags.rs @@ -0,0 +1,46 @@ +use core::{cell::UnsafeCell, fmt::Debug}; + +/// 一个无锁的标志位 +/// +/// 可与bitflags配合使用,以实现无锁的标志位 +/// +/// ## Safety +/// +/// 由于标识位的修改是无锁,且不保证原子性,因此需要使用者自行在别的机制中,确保 +/// 哪怕标识位的值是老的,执行动作也不会有问题(或者有状态恢复机制)。 +pub struct LockFreeFlags { + inner: UnsafeCell, +} + +impl LockFreeFlags { + 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 Sync for LockFreeFlags {} +unsafe impl Send for LockFreeFlags {} + +impl Clone for LockFreeFlags { + fn clone(&self) -> Self { + unsafe { Self::new(self.get().clone()) } + } +} + +impl Debug for LockFreeFlags { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("LockFreeFlags") + .field("inner", self.get()) + .finish() + } +} diff --git a/kernel/src/libs/mod.rs b/kernel/src/libs/mod.rs index ac5e208c8..f511deea6 100644 --- a/kernel/src/libs/mod.rs +++ b/kernel/src/libs/mod.rs @@ -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; diff --git a/kernel/src/libs/rwlock.rs b/kernel/src/libs/rwlock.rs index c1f183c60..23dd651d5 100644 --- a/kernel/src/libs/rwlock.rs +++ b/kernel/src/libs/rwlock.rs @@ -265,6 +265,20 @@ impl RwLock { return r; } + #[allow(dead_code)] + pub fn try_upgradeable_read_irqsave(&self) -> Option> { + 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> { // 获得UPGRADER守卫不需要查看读者位 // 如果获得读者锁失败,不需要撤回fetch_or的原子操作 diff --git a/kernel/src/main.c b/kernel/src/main.c index 20390bcaf..d7251ea3a 100644 --- a/kernel/src/main.c +++ b/kernel/src/main.c @@ -28,7 +28,7 @@ #include "driver/multiboot2/multiboot2.h" #include