Following comments in r242565 add the possibility to specify ecx when

performing cpuid calls.
Add also a new way to specify the level type to cpucontrol(8) as
reported in the manpage.

Sponsored by:	EMC / Isilon storage division
Reviewed by:	bdrewery, gcooper
Testerd by:	bdrewery
This commit is contained in:
Attilio Rao 2014-06-19 21:54:41 +00:00
parent 39c18ce157
commit aa1cb7501f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=267651
5 changed files with 98 additions and 9 deletions

View File

@ -86,19 +86,27 @@ Set/clear MSR bits according to the mask given in the
.Va data .Va data
field. field.
.It Dv CPUCTL_CPUID Fa cpuctl_cpuid_args_t *args .It Dv CPUCTL_CPUID Fa cpuctl_cpuid_args_t *args
.It Dv CPUCTL_CPUID_COUNT Fa cpuctl_cpuid_args_t *args
Retrieve CPUID information. Retrieve CPUID information.
Arguments are supplied in Arguments are supplied in
the following struct: the following struct:
.Bd -literal .Bd -literal
typedef struct { typedef struct {
int level; /* CPUID level */ int level; /* CPUID level */
int level_type; /* CPUID level type */
uint32_t data[4]; uint32_t data[4];
} cpuctl_cpuid_args_t; } cpuctl_cpuid_args_t;
.Ed .Ed
.Pp .Pp
The The
.Va level .Va level
field indicates the CPUID level to retrieve information for, while the field indicates the CPUID level to retrieve.
The
.Va level_type
field indicates the CPUID level type to retrieve.
It is overriden to 0 for
.Va CPUCTL_CPUID .
Finally, the
.Va data .Va data
field is used to store the received CPUID data. field is used to store the received CPUID data.
.It Dv CPUCTL_UPDATE cpuctl_update_args_t *args .It Dv CPUCTL_UPDATE cpuctl_update_args_t *args

View File

@ -69,6 +69,8 @@ static int cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd,
struct thread *td); struct thread *td);
static int cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, static int cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data,
struct thread *td); struct thread *td);
static int cpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_args_t *data,
struct thread *td);
static int cpuctl_do_update(int cpu, cpuctl_update_args_t *data, static int cpuctl_do_update(int cpu, cpuctl_update_args_t *data,
struct thread *td); struct thread *td);
static int update_intel(int cpu, cpuctl_update_args_t *args, static int update_intel(int cpu, cpuctl_update_args_t *args,
@ -177,6 +179,10 @@ cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
goto fail; goto fail;
ret = cpuctl_do_update(cpu, (cpuctl_update_args_t *)data, td); ret = cpuctl_do_update(cpu, (cpuctl_update_args_t *)data, td);
break; break;
case CPUCTL_CPUID_COUNT:
ret = cpuctl_do_cpuid_count(cpu, (cpuctl_cpuid_args_t *)data,
td);
break;
default: default:
ret = EINVAL; ret = EINVAL;
break; break;
@ -189,7 +195,7 @@ cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
* Actually perform cpuid operation. * Actually perform cpuid operation.
*/ */
static int static int
cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) cpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_args_t *data, struct thread *td)
{ {
int is_bound = 0; int is_bound = 0;
int oldcpu; int oldcpu;
@ -199,16 +205,25 @@ cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td)
/* Explicitly clear cpuid data to avoid returning stale info. */ /* Explicitly clear cpuid data to avoid returning stale info. */
bzero(data->data, sizeof(data->data)); bzero(data->data, sizeof(data->data));
DPRINTF("[cpuctl,%d]: retriving cpuid level %#0x for %d cpu\n", DPRINTF("[cpuctl,%d]: retrieving cpuid lev %#0x type %#0x for %d cpu\n",
__LINE__, data->level, cpu); __LINE__, data->level, data->level_type, cpu);
oldcpu = td->td_oncpu; oldcpu = td->td_oncpu;
is_bound = cpu_sched_is_bound(td); is_bound = cpu_sched_is_bound(td);
set_cpu(cpu, td); set_cpu(cpu, td);
cpuid_count(data->level, 0, data->data); cpuid_count(data->level, data->level_type, data->data);
restore_cpu(oldcpu, is_bound, td); restore_cpu(oldcpu, is_bound, td);
return (0); return (0);
} }
static int
cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td)
{
/* Override the level type. */
data->level_type = 0;
return (cpuctl_do_cpuid_count(cpu, data, td));
}
/* /*
* Actually perform MSR operations. * Actually perform MSR operations.
*/ */

View File

@ -35,7 +35,8 @@ typedef struct {
} cpuctl_msr_args_t; } cpuctl_msr_args_t;
typedef struct { typedef struct {
int level; /* CPUID level */ int level; /* CPUID level */
int level_type; /* CPUID level type */
uint32_t data[4]; uint32_t data[4];
} cpuctl_cpuid_args_t; } cpuctl_cpuid_args_t;
@ -50,5 +51,6 @@ typedef struct {
#define CPUCTL_UPDATE _IOWR('c', 4, cpuctl_update_args_t) #define CPUCTL_UPDATE _IOWR('c', 4, cpuctl_update_args_t)
#define CPUCTL_MSRSBIT _IOWR('c', 5, cpuctl_msr_args_t) #define CPUCTL_MSRSBIT _IOWR('c', 5, cpuctl_msr_args_t)
#define CPUCTL_MSRCBIT _IOWR('c', 6, cpuctl_msr_args_t) #define CPUCTL_MSRCBIT _IOWR('c', 6, cpuctl_msr_args_t)
#define CPUCTL_CPUID_COUNT _IOWR('c', 7, cpuctl_cpuid_args_t)
#endif /* _CPUCTL_H_ */ #endif /* _CPUCTL_H_ */

View File

@ -65,6 +65,12 @@ device
.Ek .Ek
.Nm .Nm
.Op Fl vh .Op Fl vh
.Fl i Ar level,level_type
.Bk
.Ar device
.Ek
.Nm
.Op Fl vh
.Op Fl d Ar datadir .Op Fl d Ar datadir
.Fl u .Fl u
.Bk .Bk
@ -114,6 +120,9 @@ In this case the inverted value of mask will be used.
.It Fl i Ar level .It Fl i Ar level
Retrieve CPUID info. Retrieve CPUID info.
Level should be given as a hex number. Level should be given as a hex number.
.It Fl i Ar level,level_type
Retrieve CPUID info.
Level and level_type should be given as hex numbers.
.It Fl u .It Fl u
Apply CPU firmware updates. Apply CPU firmware updates.
The The

View File

@ -99,6 +99,7 @@ static struct ucode_handler {
static void usage(void); static void usage(void);
static int isdir(const char *path); static int isdir(const char *path);
static int do_cpuid(const char *cmdarg, const char *dev); static int do_cpuid(const char *cmdarg, const char *dev);
static int do_cpuid_count(const char *cmdarg, const char *dev);
static int do_msr(const char *cmdarg, const char *dev); static int do_msr(const char *cmdarg, const char *dev);
static int do_update(const char *dev); static int do_update(const char *dev);
static void datadir_add(const char *path); static void datadir_add(const char *path);
@ -112,7 +113,7 @@ usage(void)
if (name == NULL) if (name == NULL)
name = "cpuctl"; name = "cpuctl";
fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | "
"-i level | -u] device\n", name); "-i level | -i level,level_type | -u] device\n", name);
exit(EX_USAGE); exit(EX_USAGE);
} }
@ -169,6 +170,57 @@ do_cpuid(const char *cmdarg, const char *dev)
return (0); return (0);
} }
static int
do_cpuid_count(const char *cmdarg, const char *dev)
{
char *cmdarg1, *endptr, *endptr1;
unsigned int level, level_type;
cpuctl_cpuid_args_t args;
int fd, error;
assert(cmdarg != NULL);
assert(dev != NULL);
level = strtoul(cmdarg, &endptr, 16);
if (*cmdarg == '\0' || *endptr == '\0') {
WARNX(0, "incorrect or missing operand: %s", cmdarg);
usage();
/* NOTREACHED */
}
/* Locate the comma... */
cmdarg1 = strstr(endptr, ",");
/* ... and skip past it */
cmdarg1 += 1;
level_type = strtoul(cmdarg1, &endptr1, 16);
if (*cmdarg1 == '\0' || *endptr1 != '\0') {
WARNX(0, "incorrect or missing operand: %s", cmdarg);
usage();
/* NOTREACHED */
}
/*
* Fill ioctl argument structure.
*/
args.level = level;
args.level_type = level_type;
fd = open(dev, O_RDONLY);
if (fd < 0) {
WARN(0, "error opening %s for reading", dev);
return (1);
}
error = ioctl(fd, CPUCTL_CPUID_COUNT, &args);
if (error < 0) {
WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev);
close(fd);
return (error);
}
fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x "
"0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1],
args.data[2], args.data[3]);
close(fd);
return (0);
}
static int static int
do_msr(const char *cmdarg, const char *dev) do_msr(const char *cmdarg, const char *dev)
{ {
@ -414,7 +466,10 @@ main(int argc, char *argv[])
c = flags & (FLAG_I | FLAG_M | FLAG_U); c = flags & (FLAG_I | FLAG_M | FLAG_U);
switch (c) { switch (c) {
case FLAG_I: case FLAG_I:
error = do_cpuid(cmdarg, dev); if (strstr(cmdarg, ",") != NULL)
error = do_cpuid_count(cmdarg, dev);
else
error = do_cpuid(cmdarg, dev);
break; break;
case FLAG_M: case FLAG_M:
error = do_msr(cmdarg, dev); error = do_msr(cmdarg, dev);