Find the answer to your Linux question:
Results 1 to 3 of 3
Here is a Kernel module written to read and write the msr for Intel processors. The header file msrdrv.h is: Code: #include <linux/ioctl.h> #include <linux/types.h> #define DEV_NAME "msrdrv" #define DEV_MAJOR ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Jan 2014
    Posts
    11

    Reading and Writing Model Specific Registers


    Here is a Kernel module written to read and write the msr for Intel processors. The header file msrdrv.h is:

    Code:
    #include <linux/ioctl.h>
     #include <linux/types.h>
     #define DEV_NAME "msrdrv"
     #define DEV_MAJOR 223
     #define DEV_MINOR 0
     #define MSR_VEC_LIMIT 32
    
    enum MsrOperation {
    MSR_NOP   = 0,
    MSR_READ  = 1,
    MSR_WRITE = 2,
    MSR_STOP  = 3,
    MSR_RDTSC = 4
    };
    
    struct MsrInOut {
    unsigned int op;              // MsrOperation
    unsigned int ecx;             // msr identifier
    union msr_union {
        struct msr_struct{
            unsigned int eax;     // low double word
            unsigned int edx;     // high double word
        }mstruct;
        unsigned long long value; // quad word
    }munion;
    };
    The module file msrdrv.c:
    Code:
    #include <linux/module.h>      // for all modules 
    #include <linux/init.h>        // for entry/exit macros 
    #include <linux/kernel.h>      // for printk priority macros 
    #include "msrdrv.h"
    
    static long long read_msr(unsigned int ecx) {
    unsigned int edx = 0, eax = 0;
    unsigned long long result = 0;
    __asm__ __volatile__("rdmsr" : "=a"(eax), "=d"(edx) : "c"(ecx));
    result = eax | (unsigned long long)edx << 0x20;
    printk(KERN_ALERT "Module msrdrv: Read 0x%016llx (0x%08x:0x%08x) from MSR 0x%08x\n", result, edx, eax, ecx);
    return result;
    }
    
    static void write_msr(int ecx, unsigned int eax, unsigned int edx) {
    printk(KERN_ALERT "Module msrdrv: Writing 0x%08x:0x%08x to MSR 0x%04x\n", edx, eax, ecx);
    __asm__ __volatile__("wrmsr" : : "c"(ecx), "a"(eax), "d"(edx));
    }
    
    static long long read_tsc(void)
    {
    unsigned eax, edx;
    long long result;
    __asm__ __volatile__("rdtsc" : "=a"(eax), "=d"(edx));
    result = eax | (unsigned long long)edx << 0x20;
    printk(KERN_ALERT "Module msrdrv: Read 0x%016llx (0x%08x:0x%08x) from TSC\n", result, edx, eax);
    return result;
    }
    
    static long msrdrv_test(unsigned long long ioctl_param, int n)
    {
    struct MsrInOut *msrops;
    int i;
    msrops = (struct MsrInOut*)ioctl_param;
    for (i = 0 ; i <= n ; i++) {
        switch (msrops[i].op) {
        case MSR_NOP:
            break;
        case MSR_STOP:
            goto label_end;
        case MSR_READ:
            msrops[i].munion.value = read_msr(msrops[i].ecx);
            break;
        case MSR_WRITE:
            write_msr(msrops[i].ecx, msrops[i].munion.mstruct.eax, msrops[i].munion.mstruct.edx);
            break;
        case MSR_RDTSC:
            msrops[i].munion.value = read_tsc();
            break;
        default:
            return 1;
        }
    }
    label_end:
    
    return 0;
    }
    
    static int msrdrv_init(void)
    {
    int i=0;
    int a=555;
    
    struct MsrInOut msr_start[] = {
        { MSR_WRITE, 0x38F, 0x00, 0x00 },       // ia32_perf_global_ctrl: disable 4 PMCs & 3 FFCs
        { MSR_WRITE, 0xc1, 0x00, 0x00 },        // ia32_pmc0: zero value (35-5)
        { MSR_WRITE, 0xc2, 0x00, 0x00 },        // ia32_pmc1: zero value (35-5)
        { MSR_WRITE, 0xc3, 0x00, 0x00 },        // ia32_pmc2: zero value (35-5)
        { MSR_WRITE, 0xc4, 0x00, 0x00 },        // ia32_pmc3: zero value (35-5)
    { MSR_WRITE, 0x186, 0x004101c2, 0x00 }, // ia32_perfevtsel1, UOPS_RETIRED.ALL (19-28)
        { MSR_WRITE, 0x187, 0x0041010e, 0x00 }, // ia32_perfevtsel0, UOPS_ISSUED.ANY (19.22)
        { MSR_WRITE, 0x188, 0x01c1010e, 0x00 }, // ia32_perfevtsel2, UOPS_ISSUED.ANY-stalls (19-22)
        { MSR_WRITE, 0x189, 0x004101a2, 0x00 }, // ia32_perfevtsel3, RESOURCE_STALLS.ANY (19-27)
        { MSR_WRITE, 0x38F, 0x0f, 0x07 },       // ia32_perf_global_ctrl: enable 4 PMCs & 3 FFCs
        { MSR_STOP, 0x00, 0x00 }
    };
    
    struct MsrInOut msr_stop[] = {
        { MSR_WRITE, 0x38F, 0x00, 0x00 },       // ia32_perf_global_ctrl: disable 4 PMCs & 3 FFCs
        { MSR_READ, 0xc1, 0x00 ,0x00},               // ia32_pmc0: read value (35-5)
        { MSR_READ, 0xc2, 0x00 ,0x00},               // ia32_pmc1: read value (35-5)
        { MSR_READ, 0xc3, 0x00 ,0x00},               // ia32_pmc2: read value (35-5)
        { MSR_READ, 0xc4, 0x00 , 0x00 },               // ia32_pmc3: read value (35-5)
        { MSR_STOP, 0x00, 0x00 }
    };
    
    
    printk(KERN_ALERT "Module " DEV_NAME " loaded\n");
    msrdrv_test((unsigned long long)msr_start,11);
    printk("uops retired:    %7lld\n", msr_stop[1].munion.value);
    printk("uops issued:     %7lld\n", msr_stop[2].munion.value);
    printk("stalled cycles:  %7lld\n", msr_stop[3].munion.value);
    printk("resource stalls: %7lld\n", msr_stop[4].munion.value);
    
    printk("This is a hex number 0x%x\n", -1);
    while(i<1000000){
    i++;
    }
    msrdrv_test((unsigned long long)msr_stop,6);
    printk("uops retired:    %7lld\n", msr_stop[1].munion.value);
    printk("uops issued:     %7lld\n", msr_stop[2].munion.value);
    printk("stalled cycles:  %7lld\n", msr_stop[3].munion.value);
    printk("resource stalls: %7lld\n", msr_stop[4].munion.value);
    return 0;
    }
    
    static void msrdrv_exit(void)
    {
    printk(KERN_ALERT "Module " DEV_NAME " unloaded\n");
    return;
    }
    
    module_init(msrdrv_init);
    module_exit(msrdrv_exit);
    The output should be the values of the counters. However, the module is giving the output for the event stalled cycles only (counter c3). It is not giving the values for other three events. Pls help me to solve the issue for why it is only reading the stalled cycles only.

  2. #2
    Linux Engineer
    Join Date
    Dec 2013
    Posts
    1,282
    From the Intel manual (for rdmsr):
    The CPUID instruction should be used to determine whether MSRs are supported (CPUID.01H:EDX[5] = 1) before
    using this instruction.

    Did you do this? Perhaps you can provide some reference and output. What is it returning and what do you expect it to return?

  3. #3
    Just Joined!
    Join Date
    Jan 2014
    Posts
    11
    Thanks @gregm for ur instant replies and giving hope that the thread can be solved.
    First, here is the cpuid instruction code that i have used:
    Code:
    #include <stdio.h>
    int main(void)
    {
        unsigned eax,edx;
        __asm__ __volatile__("cpuid" : "=a"(eax) : "a"(0x01));
        printf("edx:  %x\n", edx);
       return 0;
    }
    The output for this is : edx: 3f4ff4

    Now, for the original thread, the output is :
    uops retired: 0
    uops issued: 0
    stalled cycles: 10214
    resource stalls: 0

    The value for stalled cycles keep changing on every new execution but the values for the other three events always remain 0.
    Now, the problem is that when the 'while loop' is being executed, some of the uops must be issued as well as retired; then why the values corresponding to these events is always 0. So i expect some values for these events and other events like branch instructions executed.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •