/*!
 * @fn void cpumon_Save_Cpu(param)
 *
 * @param  param - Unused, set up to enable parallel calls
 *
 * @return None     No return needed
 *
 * @brief  Set up the interrupt handler.  
 * @brief  Save the old handler for restoration when done
 *
 */
static VOID 
cpumon_Save_Cpu (
    PVOID parm
)
{
    unsigned long        eflags;
    IDTGDT_DESC          idt_base;
    CPU_STATE            pcpu = &pcb[CONTROL_THIS_CPU()];
    GATE_STRUCT          old_gate;
    GATE_STRUCT         *idt;

    SYS_Local_Irq_Save(eflags);
    SYS_Get_IDT_Base((PVOID*)&idt_base);
    idt  = idt_base.idtgdt_base;

    CPU_STATE_idt_base(pcpu) = idt;
    memcpy (&old_gate, &idt[CPU_PERF_VECTOR], 16);

    CPU_STATE_saved_ih(pcpu)  = (PVOID) ((((U64) old_gate.offset_high) << 32)   | 
                                         (((U64) old_gate.offset_middle) << 16) | 
                                          ((U64) old_gate.offset_low));
 
    SEP_PRINT_DEBUG("saved_ih is 0x%llx\n", CPU_STATE_saved_ih(pcpu));
    SYS_Local_Irq_Restore(eflags);

    return;
}
/*!
 * @fn void cpumon_Save_Cpu(param)
 *
 * @param    param    unused parameter
 *
 * @return   None     No return needed
 *
 * @brief  Save the old handler for restoration when done
 *
 */
static void 
cpumon_Save_Cpu (
    PVOID parm
)
{
    unsigned long        eflags;
    U64                 *idt_base;
    CPU_STATE            pcpu;

    preempt_disable();
    pcpu = &pcb[CONTROL_THIS_CPU()];
    preempt_enable();

    SYS_Local_Irq_Save(eflags);
    CPU_STATE_idt_base(pcpu) = idt_base = SYS_Get_IDT_Base();
    // save original perf. vector
    CPU_STATE_saved_ih(pcpu) = idt_base[CPU_PERF_VECTOR];
    SEP_PRINT_DEBUG("saved_ih is 0x%llx\n", CPU_STATE_saved_ih(pcpu));
    SYS_Local_Irq_Restore(eflags);
    return;
}
Example #3
0
/*!
 * @fn void cpumon_Destroy_Cpu(param)
 *
 * @param    param    unused parameter
 *
 * @return   None     No return needed
 *
 * @brief  Restore the old handler
 * @brief  Finish clean up of the apic
 *
 */
static VOID 
cpumon_Destroy_Cpu (
    PVOID ctx
)
{
    unsigned long        eflags;
    unsigned long long  *idt_base;
    CPU_STATE            pcpu;
    preempt_disable();
    pcpu = &pcb[CONTROL_THIS_CPU()];
    preempt_enable();

    SYS_Local_Irq_Save(eflags);
    // restore perf. vector (to a safe stub pointer)
    idt_base = SYS_Get_IDT_Base();
    APIC_Disable_PMI();
    idt_base[CPU_PERF_VECTOR] = CPU_STATE_saved_ih(pcpu);
    SYS_Local_Irq_Restore(eflags);

    return;
}
/*!
 * @fn void cpumon_Destroy_Cpu(param)
 *
 * @param    param    unused parameter
 *
 * @return   None     No return needed
 *
 * @brief  Restore the old handler
 * @brief  Finish clean up of the apic
 *
 */
static VOID 
cpumon_Destroy_Cpu (
    PVOID ctx
)
{
    unsigned long        eflags;
    unsigned long long  *idt_base;
    CPU_STATE            pcpu;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    unsigned long        cr0_value;
#endif

    preempt_disable();
    pcpu = &pcb[CONTROL_THIS_CPU()];
    preempt_enable();

    SYS_Local_Irq_Save(eflags);
    // restore perf. vector (to a safe stub pointer)
    idt_base = SYS_Get_IDT_Base();
    APIC_Disable_PMI();

    // From 3.10 kernel, the IDT memory has been moved to a read-only location
    // which is controlled by the bit 16 in the CR0 register.
    // The write protection should be temporarily released to update the IDT.
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    cr0_value = read_cr0();
    write_cr0(cr0_value & ~X86_CR0_WP);
#endif
    idt_base[CPU_PERF_VECTOR] = CPU_STATE_saved_ih(pcpu);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
    write_cr0(cr0_value);
#endif

    SYS_Local_Irq_Restore(eflags);

    return;
}