/*
 * ewbe.c
 * Short program by Dave Jones <davej@suse.de> to manipulate
 * the EWBE register found in AMD K6-2 & K6-3
 *
 * *nb*, no checking for cpu type added, you should ONLY run this
 * on the above named CPUs.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int rdmsr(int cpu, unsigned int index, unsigned long long *val)
{
	char cpuname[16];
	unsigned char buffer[8];
	unsigned long lo, hi;
	int fh;

	sprintf (cpuname, "/dev/cpu/%d/msr", cpu);

	fh = open (cpuname, O_RDONLY);
	if (fh==-1)
		return (0);

	lseek (fh, index, SEEK_CUR);

	if (fh != -1) {

		if (read (fh, &buffer[0], 8) != 8) {
			close (fh);
			return (0);
		}

		lo = (*(unsigned long *)buffer);
		hi = (*(unsigned long *)(buffer+4));
		*val = hi;
		*val = *val<<32 | lo;
	}
	close (fh);
	return (1);
}


int wrmsr(int cpu, unsigned int index, unsigned long long *val)
{
	char cpuname[16];
	unsigned char buffer[8];
	int fh;

	sprintf (cpuname, "/dev/cpu/%d/msr", cpu);

	fh = open (cpuname, O_WRONLY);
	if (fh==-1)
		return (0);

	lseek (fh, index, SEEK_CUR);

	if (fh != -1) {

		(*(unsigned long long *)buffer) = *val;
		if (write (fh, &buffer[0], 8) != 8) {
			close (fh);
			return (0);
		}
	}
	close (fh);
	return (1);
}

#define EWBE_SLOWEST 0
#define EWBE_CLOSE_TO_BEST 1<<2
#define EWBE_FASTEST (1<<2|1<<3)

int main (void)
{
	unsigned long long val=0, val2;

	if (rdmsr(0, 0xC0000080, &val) != 1) {
		printf ("Couldn't read MSR\n");
		return -1;
	}

	printf ("HWCR=%16llx\n", val);

	printf ("Current EWBE mode is ");
	val2 = (val & (1<<2 | 1<<3))>>2;
	switch (val2) {
	case 0:	printf ("strong ordering\n");
			break;
	case 1:	printf ("speculative disable\n");
			break;
	case 2:	printf ("invalid\n");
			break;
	case 3:	printf ("global disable\n");
			break;
	}	

//	val = val & ~(1<<2|1<<3);	/* mask out current state */
//	val = val | EWBE_SLOWEST;

//	wrmsr (0, 0xC0000080, &val); 
//	printf ("Register changed to %16llx\n", val);

	return (0);
}
