A struct mtrr_gentry is passed to the ioctl() with the regnum member set to the MTRR register one wants to read. After a successful ioctl() call, size member of struct mtrr_gentry is less than 1 if the MTRR is disabled, otherwise it is populated with the MTRR register configuration.
Below is an example showing how to use MTRRIOC_GET_ENTRY:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <asm/mtrr.h>
#include <fcntl.h>
#define LONGSZ ((int)(sizeof(long)<<1))
int main(int argc, char *argv[])
{
struct mtrr_gentry gentry;
int fd;
static char *mtrr_type[] = {
"Uncachable",
"Write Combining",
"Unknown",
"Unknown",
"Write Through",
"Write Protect",
"Write Back"
};
if ((fd = open("/proc/mtrr", O_RDONLY, 0)) < 0) {
fprintf(stderr, "Cannot open /proc/mtrr!\n");
exit(EXIT_FAILURE);
}
memset(&gentry, 0, sizeof(gentry));
while (!ioctl(fd, MTRRIOC_GET_ENTRY, &gentry)) {
if (gentry.size < 1)
printf("%u: Disabled\n", gentry.regnum);
else
printf("%u: 0x%*.*lx..0x%*.*lx %s\n", gentry.regnum,
LONGSZ, LONGSZ, gentry.base,
LONGSZ, LONGSZ, gentry.base + gentry.size,
mtrr_type[gentry.type]);
gentry.regnum++;
}
close(fd);
exit(EXIT_SUCCESS);
}
The downside to using MTRRIOC_GET_ENTRY is that MTRR base addresses > 4GB get returned as zero, which is a known "feature" of this interface - the offending code in mtrr_ioctl() in arch/x86/kernel/cpu/mtrr/if.c is as follows:
/* Hide entries that go above 4GB */
if (gentry.base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))
|| size >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT)))
gentry.base = gentry.size = gentry.type = 0;
else {
gentry.base <<= PAGE_SHIFT;
gentry.size = size << PAGE_SHIFT;
gentry.type = type;
}
..clearly showing that gentry.base, .size and .type are set to zero for entries > 4GB.
No comments:
Post a Comment