trouble with pmi handle on windows 7

1

I am trying to set up performance monitorint interrupt on counter overflow to collect some information. For this I created driver. I skip some part of code that are irrelevant.

driver.c

extern VOID EnableReadPmc();
extern VOID PmiHandle();
extern VOID GetIdt(IDT_INFO *idt);
extern ULONG64 GetCs();

#pragma pack(2)
typedef struct {
    USHORT Limit;
    ULONG64 Base;
}IDT_INFO;
#pragma pack()

typedef struct _entry {
    ULONG64 Low;
    ULONG64 High;
} entry;

PHYSICAL_ADDRESS lvt_perf_count_reg = {0xfee00340, 0x00000000};
PVOID map_lvt_perf_count_reg = NULL;
PHYSICAL_ADDRESS eoi_register = {0xfee000b0, 0x00000000};
PVOID map_eoi_register = NULL;

NTSTATUS IoCtlDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) {
    ULONG32 set_lvt_perf_count_reg = 0x000000ee;        
    //idt
    IDT_INFO idtr;
    entry *idt = NULL;
    entry tmp_gate;
    ULONG64 func;
    ULONG64 seg;
    ULONG64 int_setting;
    //ovf status value
    ULONG64 ovf_status;

    pIrpStack = IoGetCurrentIrpStackLocation(pIrp);

    switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) {

    case IOCTL_INTERRUPT_SETTING_UP:
        //disable pmc and clear ovf
        WriteMsr(IA32_PERF_GLOBAL_CTRL, 0x00);
        WriteMsr(IA32_FIXED_CTR_CTRL, 0x00);
        ovf_status = ReadMsr(IA32_PERF_GLOBAL_STATUS);
        WriteMsr(IA32_PERF_GLOBAL_OVF_CTRL, ovf_status);

        //setting up lvt entry       
        map_lvt_perf_count_reg = MmMapIoSpace(lvt_perf_count_reg, 4, MmNonCached);
        *(PULONG32)map_lvt_perf_count_reg = set_lvt_perf_count_reg;

        map_eoi_register = MmMapIoSpace(eoi_register, 4, MmNonCached);

        //setting up idt handler
        idtr.Limit = 0;
        idtr.Base = 0;
        GetIdt(&idtr);
        idt = idtr.Base;

        tmp_gate.Low = 0;
        tmp_gate.High = 0;
        func = 0;
        seg = 0;
        int_setting = 0x8e00;
        //p = 1   dpl = 0   type(interrupt gate) = 1110   ist = 0
        seg = GetCs();
        func = (ULONG64)PmiHandle;
        tmp_gate.Low = func & 0x0ffff;
        tmp_gate.Low = seg << 16 | tmp_gate.Low;
        tmp_gate.Low = int_setting << 32 | tmp_gate.Low;

        tmp_gate.Low = ((func & 0x0ffff0000) << 32) | tmp_gate.Low;
        tmp_gate.High = (func & 0xffffffff00000000) >> 32;

        idt[238] = tmp_gate;

        MmUnmapIoSpace(map_lvt_perf_count_reg, 4);
        map_lvt_perf_count_reg = NULL;

        pIrp->IoStatus.Information = 0;
        break;


    default:
        DbgPrint("Error in switch");
        break;
    }

    status = pIrp->IoStatus.Status;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

    return status;
}

pmihandle.asm

public PmiHandle
extern Handle : proc

.code
PmiHandle:
    call Handle
    add rsp, 8
    iretq
end

handle.c

#define IA32_PERF_GLOBAL_CTRL 0x38f
#define IA32_PERF_GLOBAL_STATUS 0x38e
#define IA32_PERF_GLOBAL_OVF_CTRL 0x390

extern ULONG64 ovf_status_handle;
extern PVOID map_eoi_register;

VOID Handle() {
    WriteMsr(IA32_PERF_GLOBAL_CTRL, 0x00);
    ovf_status_handle = ReadMsr(IA32_PERF_GLOBAL_STATUS);
    WriteMsr(IA32_PERF_GLOBAL_OVF_CTRL, ovf_status_handle);

    DbgPrint("INTERRUPT_INTERRUPT_INTERRUPT");

    if (map_eoi_register != NULL)
        *(PULONG32)map_eoi_register = 0x0;
    else
      DbgPrint("EOI failed");  
}

main.c application with which I turn on counters

#include <stdio.h>

#include "include/msr_sampling.h"

#define FILE_DEVICE_MSR 0x8000
#define IOCTL_INTERRUPT_SETTING_UP CTL_CODE(FILE_DEVICE_MSR, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_FILE_TEST CTL_CODE(FILE_DEVICE_MSR, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)

int main() {
    SetProcForMsrCtr(); //set affinity mask for first proc

    DriverOpen();

    EnableReadPmc(); //enable __readpmc instruction
    DWORD numberData = -1;
    DeviceIoControl(hFile, IOCTL_INTERRUPT_SETTING_UP, NULL, 0, NULL, 0, &numberData, NULL);

    ULONG64 value;
    value = 0x000000000000000b;
    WriteMsr(IA32_FIXED_CTR_CTRL, value);

    value = 0xfffffffff000; //old value ffffffffc000
    printf("%llu\n", __readpmc((1 << 30)));
    WriteMsr(0x309, value);
    printf("%llx\n", __readpmc((1 << 30)));
    printf("=================================================\n");
    ReadMsr(IA32_PERF_GLOBAL_CTRL, &value);
    printf("%llX\n", value);
    value = 0x0000000100000000;
    WriteMsr(IA32_PERF_GLOBAL_CTRL, value);
    printf("counter value: %llX\n", __readpmc((1 << 30)));

    DriverClose();

    system("pause");
    return 0;
}

When I launch application my computer froze(does not respond to mouse movement and press key).

But if I generate interrupt with using assembly instuction INT it is OK.

I checked IDT and LVT entry via WinDbg they are correct.

What could be the problem?

Some informantion: My processor is Intel Core i5-3210M. OS windows 7 x64. I do this on laptop.

monitoring
interrupt
performancecounter
interrupt-handling
intel-pmu
asked on Stack Overflow Dec 18, 2019 by axint4

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0