#include "apic.h" #include "apic_timer.h" #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 中断服务程序 * * @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