/*
*  p6uc - Update Intel Microcode on P6 processors.
*
*  Copyright (C) 2000, Tigran Aivazian (GPL v2, as usual)
*
*  Reference: Section 8.10 of Volume III,
*  Intel Pentium III Manual, Order Number 243192.
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>

#include <asm/mtrr.h>

struct mtrr_p6update ioc;
void * ucode;
static char * myname;

static void die(const char * fmt, ...);

int main(int argc, char *argv[])
{
       int fd;
       struct stat st;

       myname = argv[0];

       if (argc != 2) {
               fprintf(stderr, "usage: %s [mcode_file]\n", argv[0]);
               exit(1);
       }

       fd = open(argv[1], O_RDONLY);
       if (fd == -1)
               die("open(%s)", argv[1]);
       if (fstat(fd, &st) == -1)
               die("fstat(fd=%d)", fd);
       if (st.st_size == 0 || (st.st_size % sizeof(struct p6ucode) != 0)) {
               fprintf(stderr, "%s: corrupted microcode in '%s' or 'struct p6ucode' "
                               "in <asm/mtrr.h> needs updating\n", argv[0], argv[1]);
               exit(1);
       }
       ucode = malloc(st.st_size);
       if (!ucode)
               die("Can't malloc(%ld) to hold microcode\n", st.st_size);
       if (read(fd, ucode, st.st_size) != st.st_size)
               die("read(fd, ucode, %ld)", st.st_size);
       if (close(fd) == -1)
               die("close(fd=%d)", fd);
       fd = open("/proc/mtrr", O_RDONLY);
       if (fd == -1)
               die("open(/proc/mtrr)");
       ioc.num = st.st_size/sizeof(struct p6ucode);
       ioc.uaddr = ucode;
       if (ioctl(fd, MTRRIOC_P6UPDATE, &ioc) == -1)
               die("ioctl(MTRRIOC_P6UPDATE, num=%d)", ioc.num);
       if (close(fd) == -1)
               die("close(fd=%d)", fd);
       return 0;
}

static void die(const char * fmt, ...)
{
       va_list args;
       static char buf[4096];

       va_start(args, fmt);
       vsprintf(buf, fmt, args);
       va_end(args);

       fprintf(stderr, "%s: %s, errno=%d (%s)\n",
               myname, buf, errno, strerror(errno));
       exit(1);
}