diff --git a/README.md b/README.md index 3812549..f2d92c7 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,8 @@ unheard-of. Starting in version 2.0.0, the __version__ field will be compared to the version of the loaded kernel module with a mismatch -resulting in an error. Earlier versions do not check this field. +in the major version number resulting in an error. +Earlier versions do not check this field. Each op is contained in a __struct msr_batch_op__: @@ -292,17 +293,11 @@ Requested virtual CPU does not exist or is offline. ### /dev/cpu/msr_batch ### **ioctl(2)** +Verifying the batch request can result in the following errors. -All of the operations in the batch will be executed. Each operation may result -in an __EIO__, __ENXIO__, __EACCES__, or __EROFS__ error, which will be -recorded in the __msr_batch_op__ struct. If any operation caused an error, the -first such error becomes the return value for **ioctl(2)**. - -__E2BIG__ -Kernel unable to allocate memory to hold the array of operations. - -__EACCES__ -An individual operation requested an MSR that is not present in the allowlist. +__ENOTTY__ +Invalid ioctl command. As of this writing the only ioctl command +supported on this device is __X86_IOC_MSR_BATCH__, defined in __msr_safe.h__. __EBADF__ The __msr_batch__ file was not opened for reading. @@ -311,7 +306,25 @@ __EFAULT__ Kernel **copy_from_user()** or **copy_to_user()** failed. __EINVAL__ -Number of requested batch operations is <=0. +Number of requested batch operations is 0. + +__ENOPROTOOPT__ +There is a mismatch between the major version number of the currently-loaded +msr-safe kernel module and the version number requested by the batch struct. + +__E2BIG__ +Kernel unable to allocate memory to hold the array of operations. + +__ENOMEM__ +Kernel unable to allocate memory to hold the results of __zalloc_cpumask_var()__. + +If all is well, all of the operations in the batch will be executed. If an +individual operation results in one of the following errors, the error will +be recorded in its __msr_batch_op__ struct. The first of these errors will +become the return value for **ioctl(2)**. + +__EACCES__ +An individual operation requested an MSR that is not present in the allowlist. __EIO__ A general protection fault occurred. On Intel processors this @@ -320,13 +333,6 @@ attempting to access a non-existent or reserved MSR address, c) writing 1-bits to a reserved area of an MSR, d) writing a non-canonical address to MSRs that take memory addresses, or e) writing to MSR bits that are marked as read-only. -__ENOMEM__ -Kernel unable to allocate memory to hold the results of __zalloc_cpumask_var()__. - -__ENOTTY__ -Invalid ioctl command. As of this writing the only ioctl command -supported on this device is __X86_IOC_MSR_BATCH__, defined in __msr_safe.h__. - __ENXIO__ An individual operation requested a virtual CPU does not exist or is offline. diff --git a/examples/example.c b/examples/example.c index edf2387..ed7d10d 100644 --- a/examples/example.c +++ b/examples/example.c @@ -26,13 +26,14 @@ #include // exit(3) #include // ioctl(2) -#include "../msr_safe.h" // batch data structs +#include "../msr_safe.h" // batch data structs +#include "../msr_version.h" // MSR_SAFE_VERSION_u32 #define MSR_MPERF 0xE7 char const *const allowlist = "0xE7 0xFFFFFFFFFFFFFFFF\n"; // MPERF -static uint8_t const nCPUs = 32; +static uint8_t const nCPUs = 16; void set_allowlist() { @@ -74,7 +75,7 @@ void measure_serial_latency() // Show results printf("Serial cycles from first write to last read:" - "%"PRIu64" (on %"PRIu8" CPUs)\n", + "%9"PRIu64" (on %"PRIu8" CPUs)\n", data[nCPUs - 1], nCPUs); } @@ -95,7 +96,8 @@ void measure_batch_latency() r_ops[i].msr = w_ops[i].msr = MSR_MPERF; w_ops[i].msrdata = 0; } - rbatch.numops = wbatch.numops = nCPUs; + rbatch.numops = wbatch.numops = nCPUs; + rbatch.version = wbatch.version = MSR_SAFE_VERSION_u32; rbatch.ops = r_ops; wbatch.ops = w_ops; @@ -104,8 +106,8 @@ void measure_batch_latency() rc = ioctl(fd, X86_IOC_MSR_BATCH, &rbatch); assert(-1 != rc); - printf("Batch cycles from first write to last read:" - "%llu (on %"PRIu8" CPUs)\n", + printf("Batch cycles from first write to last read: " + "%9llu (on %"PRIu8" CPUs)\n", r_ops[nCPUs - 1].msrdata, nCPUs); } diff --git a/msr_batch.c b/msr_batch.c index d36b728..77a0265 100644 --- a/msr_batch.c +++ b/msr_batch.c @@ -33,6 +33,7 @@ #include "msr_safe.h" #include "msr-smp.h" #include "msr_allowlist.h" +#include "msr_version.h" static struct class *cdev_class; static char cdev_created; @@ -102,12 +103,20 @@ static long msrbatch_ioctl(struct file *f, unsigned int ioc, unsigned long arg) return -EFAULT; } - if (koa.numops <= 0) + if (koa.numops == 0) { pr_debug("Invalid # of ops %d\n", koa.numops); return -EINVAL; } + if ( ((koa.version >> 16) & 0xff) != MSR_SAFE_VERSION_MAJOR ){ + pr_debug("Version mismatch: loaded is %d, requested is %d\n", + MSR_SAFE_VERSION_MAJOR, + (koa.version >> 16) & 0xff + ); + return -ENOPROTOOPT; + } + uops = koa.ops; koa.ops = kmalloc_array(koa.numops, sizeof(*koa.ops), GFP_KERNEL); diff --git a/msr_version.h b/msr_version.h index eb67b93..6551438 100644 --- a/msr_version.h +++ b/msr_version.h @@ -22,8 +22,8 @@ int msr_version_init(int *majordev); void msr_version_cleanup(int majordev); -#define MSR_SAFE_VERSION_MAJOR 1 -#define MSR_SAFE_VERSION_MINOR 8 +#define MSR_SAFE_VERSION_MAJOR 2 +#define MSR_SAFE_VERSION_MINOR 0 #define MSR_SAFE_VERSION_PATCH 0 #define MSR_SAFE_VERSION_u32 ( \