void cpu_interrupt_isr_entry(struct registers *regs, int int_no, addr_t return_address) { int already_in_kernel = 0; cpu_interrupt_set(0); atomic_fetch_add_explicit(&interrupt_counts[int_no], 1, memory_order_relaxed); if(current_thread && !current_thread->regs) { current_thread->regs = regs; current_thread->system = 255; } else already_in_kernel = 1; int started = timer_start(&interrupt_timers[int_no]); char called = 0; for(int i = 0; i < MAX_HANDLERS; i++) { if(interrupt_handlers[int_no][i].fn) { interrupt_handlers[int_no][i].fn(regs, int_no, 0); called = 1; } } if(started) timer_stop(&interrupt_timers[int_no]); cpu_interrupt_set(0); // If it went unhandled, kill the process or panic. if(!already_in_kernel) { current_thread->system = 0; } if(!called) faulted(int_no, !already_in_kernel, return_address, regs->err_code, regs); if(!already_in_kernel) { __setup_signal_handler(regs); current_thread->regs = 0; ASSERT(!current_thread || (current_process == kernel_process) || current_thread->held_locks == 0); } }
/* this should NEVER enter from an interrupt handler, * and only from kernel code in the one case of calling * sys_setup() */ void entry_syscall_handler(volatile registers_t regs) { /* don't need to save the flag here, since it will always be true */ #if CONFIG_ARCH == TYPE_ARCH_X86_64 assert(regs.int_no == 0x80 && ((regs.ds&(~0x7)) == 0x10 || (regs.ds&(~0x7)) == 0x20) && ((regs.cs&(~0x7)) == 0x8 || (regs.cs&(~0x7)) == 0x18)); #endif set_int(0); add_atomic(&int_count[0x80], 1); if(current_task->flags & TF_IN_INT) panic(0, "attempted to enter syscall while handling an interrupt"); /* set the interrupt handling flag... */ raise_flag(TF_IN_INT); #if CONFIG_ARCH == TYPE_ARCH_X86_64 if(regs.rax == 128) { #elif CONFIG_ARCH == TYPE_ARCH_X86 if(regs.eax == 128) { #endif /* the injection code at the end of the signal handler calls * a syscall with eax = 128. So here we handle returning from * a signal handler. First, copy back the old registers, and * reset flags and signal stuff */ memcpy((void *)®s, (void *)¤t_task->reg_b, sizeof(registers_t)); current_task->sig_mask = current_task->old_mask; current_task->cursig=0; lower_flag(TF_INSIG); lower_flag(TF_JUMPIN); } else { assert(!current_task->sysregs && !current_task->regs); /* otherwise, this is a normal system call. Save the regs for modification * for signals and exec */ current_task->regs = ®s; current_task->sysregs = ®s; syscall_handler(®s); assert(!get_cpu_interrupt_flag()); /* handle stage2's here...*/ if(maybe_handle_stage_2 || !current_task->syscall_count) { mutex_acquire(&s2_lock); for(int i=0;i<MAX_INTERRUPTS;i++) { if(stage2_count[i]) { sub_atomic(&stage2_count[i], 1); for(int j=0;j<MAX_HANDLERS;j++) { if(interrupt_handlers[i][j][1]) { (interrupt_handlers[i][j][1])(®s); } } } } mutex_release(&s2_lock); } assert(!get_cpu_interrupt_flag()); } assert(!set_int(0)); current_task->sysregs=0; current_task->regs=0; /* we don't need worry about this being wrong, since we'll always be returning to * user-space code */ set_cpu_interrupt_flag(1); /* we're never returning to an interrupt, so we can * safely reset this flag */ lower_flag(TF_IN_INT); #if CONFIG_SMP lapic_eoi(); #endif } /* This gets called from our ASM interrupt handler stub. */ void isr_handler(volatile registers_t regs) { #if CONFIG_ARCH == TYPE_ARCH_X86_64 assert(((regs.ds&(~0x7)) == 0x10 || (regs.ds&(~0x7)) == 0x20) && ((regs.cs&(~0x7)) == 0x8 || (regs.cs&(~0x7)) == 0x18)); #endif /* this is explained in the IRQ handler */ int previous_interrupt_flag = set_int(0); add_atomic(&int_count[regs.int_no], 1); /* check if we're interrupting kernel code, and set the interrupt * handling flag */ char already_in_interrupt = 0; if(current_task->flags & TF_IN_INT) already_in_interrupt = 1; raise_flag(TF_IN_INT); /* run the stage1 handlers, and see if we need any stage2s. And if we * don't handle it at all, we need to actually fault to handle the error * and kill the process or kernel panic */ char called=0; char need_second_stage = 0; for(int i=0;i<MAX_HANDLERS;i++) { if(interrupt_handlers[regs.int_no][i][0] || interrupt_handlers[regs.int_no][i][1]) { /* we're able to handle the error! */ called = 1; if(interrupt_handlers[regs.int_no][i][0]) (interrupt_handlers[regs.int_no][i][0])(®s); if(interrupt_handlers[regs.int_no][i][1]) need_second_stage = 1; } } if(need_second_stage) { /* we need to run a second stage handler. Indicate that here... */ add_atomic(&stage2_count[regs.int_no], 1); maybe_handle_stage_2 = 1; } /* clean up... Also, we don't handle stage 2 in ISR handling, since this can occur from within a stage2 handler */ assert(!set_int(0)); /* if it went unhandled, kill the process or panic */ if(!called) faulted(regs.int_no, !already_in_interrupt, regs.eip); /* restore previous interrupt state */ set_cpu_interrupt_flag(previous_interrupt_flag); if(!already_in_interrupt) lower_flag(TF_IN_INT); /* send out the EOI... */ #if CONFIG_SMP lapic_eoi(); #endif }