10112b52bSAndriy Gapon /*-
20112b52bSAndriy Gapon * Copyright (c) 2012 Andriy Gapon <avg@FreeBSD.org>.
30112b52bSAndriy Gapon * All rights reserved.
40112b52bSAndriy Gapon *
50112b52bSAndriy Gapon * Redistribution and use in source and binary forms, with or without
60112b52bSAndriy Gapon * modification, are permitted provided that the following conditions
70112b52bSAndriy Gapon * are met:
80112b52bSAndriy Gapon * 1. Redistributions of source code must retain the above copyright
90112b52bSAndriy Gapon * notice, this list of conditions and the following disclaimer.
100112b52bSAndriy Gapon * 2. Redistributions in binary form must reproduce the above copyright
110112b52bSAndriy Gapon * notice, this list of conditions and the following disclaimer in the
120112b52bSAndriy Gapon * documentation and/or other materials provided with the distribution.
130112b52bSAndriy Gapon *
140112b52bSAndriy Gapon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
150112b52bSAndriy Gapon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
160112b52bSAndriy Gapon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
170112b52bSAndriy Gapon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
180112b52bSAndriy Gapon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
190112b52bSAndriy Gapon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
200112b52bSAndriy Gapon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
210112b52bSAndriy Gapon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
220112b52bSAndriy Gapon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
230112b52bSAndriy Gapon * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
240112b52bSAndriy Gapon */
250112b52bSAndriy Gapon
260112b52bSAndriy Gapon #include <sys/types.h>
270112b52bSAndriy Gapon #include <sys/stat.h>
280112b52bSAndriy Gapon #include <sys/mman.h>
290112b52bSAndriy Gapon #include <sys/ioctl.h>
300112b52bSAndriy Gapon #include <sys/ioccom.h>
310112b52bSAndriy Gapon #include <sys/cpuctl.h>
320112b52bSAndriy Gapon
330112b52bSAndriy Gapon #include <machine/cpufunc.h>
340112b52bSAndriy Gapon #include <machine/specialreg.h>
350112b52bSAndriy Gapon
36*34467bd7SChuck Silvers #include <x86/ucode.h>
37*34467bd7SChuck Silvers
380112b52bSAndriy Gapon #include <assert.h>
390112b52bSAndriy Gapon #include <stdio.h>
400112b52bSAndriy Gapon #include <stdlib.h>
410112b52bSAndriy Gapon #include <string.h>
420112b52bSAndriy Gapon #include <unistd.h>
430112b52bSAndriy Gapon #include <fcntl.h>
440112b52bSAndriy Gapon #include <err.h>
450112b52bSAndriy Gapon
460112b52bSAndriy Gapon #include "cpucontrol.h"
470112b52bSAndriy Gapon #include "amd.h"
480112b52bSAndriy Gapon
490112b52bSAndriy Gapon int
amd10h_probe(int fd)500112b52bSAndriy Gapon amd10h_probe(int fd)
510112b52bSAndriy Gapon {
520112b52bSAndriy Gapon char vendor[13];
530112b52bSAndriy Gapon cpuctl_cpuid_args_t idargs;
540112b52bSAndriy Gapon uint32_t family;
550112b52bSAndriy Gapon uint32_t signature;
560112b52bSAndriy Gapon int error;
570112b52bSAndriy Gapon
580112b52bSAndriy Gapon idargs.level = 0;
590112b52bSAndriy Gapon error = ioctl(fd, CPUCTL_CPUID, &idargs);
600112b52bSAndriy Gapon if (error < 0) {
610112b52bSAndriy Gapon WARN(0, "ioctl()");
620112b52bSAndriy Gapon return (1);
630112b52bSAndriy Gapon }
640112b52bSAndriy Gapon ((uint32_t *)vendor)[0] = idargs.data[1];
650112b52bSAndriy Gapon ((uint32_t *)vendor)[1] = idargs.data[3];
660112b52bSAndriy Gapon ((uint32_t *)vendor)[2] = idargs.data[2];
670112b52bSAndriy Gapon vendor[12] = '\0';
680112b52bSAndriy Gapon if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0)
690112b52bSAndriy Gapon return (1);
700112b52bSAndriy Gapon
710112b52bSAndriy Gapon idargs.level = 1;
720112b52bSAndriy Gapon error = ioctl(fd, CPUCTL_CPUID, &idargs);
730112b52bSAndriy Gapon if (error < 0) {
740112b52bSAndriy Gapon WARN(0, "ioctl()");
750112b52bSAndriy Gapon return (1);
760112b52bSAndriy Gapon }
770112b52bSAndriy Gapon signature = idargs.data[0];
780112b52bSAndriy Gapon family = ((signature >> 8) & 0x0f) + ((signature >> 20) & 0xff);
790112b52bSAndriy Gapon if (family < 0x10)
800112b52bSAndriy Gapon return (1);
810112b52bSAndriy Gapon return (0);
820112b52bSAndriy Gapon }
830112b52bSAndriy Gapon
840112b52bSAndriy Gapon void
amd10h_update(const struct ucode_update_params * params)85dee401e8SConrad Meyer amd10h_update(const struct ucode_update_params *params)
860112b52bSAndriy Gapon {
870112b52bSAndriy Gapon cpuctl_cpuid_args_t idargs;
880112b52bSAndriy Gapon cpuctl_msr_args_t msrargs;
890112b52bSAndriy Gapon cpuctl_update_args_t args;
90dee401e8SConrad Meyer const uint8_t *fw_image;
91dee401e8SConrad Meyer const char *dev, *path;
92*34467bd7SChuck Silvers const void *selected_fw;
930112b52bSAndriy Gapon size_t fw_size;
940112b52bSAndriy Gapon size_t selected_size;
950112b52bSAndriy Gapon uint32_t revision;
960112b52bSAndriy Gapon uint32_t new_rev;
970112b52bSAndriy Gapon uint32_t signature;
98dee401e8SConrad Meyer int devfd;
990112b52bSAndriy Gapon int error;
1000112b52bSAndriy Gapon
101dee401e8SConrad Meyer dev = params->dev_path;
102dee401e8SConrad Meyer path = params->fw_path;
103dee401e8SConrad Meyer devfd = params->devfd;
104dee401e8SConrad Meyer fw_image = params->fwimage;
105dee401e8SConrad Meyer fw_size = params->fwsize;
106dee401e8SConrad Meyer
1070112b52bSAndriy Gapon assert(path);
1080112b52bSAndriy Gapon assert(dev);
1090112b52bSAndriy Gapon
1100112b52bSAndriy Gapon idargs.level = 1;
1110112b52bSAndriy Gapon error = ioctl(devfd, CPUCTL_CPUID, &idargs);
1120112b52bSAndriy Gapon if (error < 0) {
1130112b52bSAndriy Gapon WARN(0, "ioctl()");
1140112b52bSAndriy Gapon goto done;
1150112b52bSAndriy Gapon }
1160112b52bSAndriy Gapon signature = idargs.data[0];
1170112b52bSAndriy Gapon
118a18e40aaSMark Johnston msrargs.msr = MSR_BIOS_SIGN;
1190112b52bSAndriy Gapon error = ioctl(devfd, CPUCTL_RDMSR, &msrargs);
1200112b52bSAndriy Gapon if (error < 0) {
1210112b52bSAndriy Gapon WARN(0, "ioctl(%s)", dev);
1220112b52bSAndriy Gapon goto done;
1230112b52bSAndriy Gapon }
1240112b52bSAndriy Gapon revision = (uint32_t)msrargs.data;
1250112b52bSAndriy Gapon
126*34467bd7SChuck Silvers selected_fw = ucode_amd_find(path, signature, revision, fw_image,
127*34467bd7SChuck Silvers fw_size, &selected_size);
1280112b52bSAndriy Gapon
1290112b52bSAndriy Gapon if (selected_fw != NULL) {
1300112b52bSAndriy Gapon WARNX(1, "selected ucode size is %zu", selected_size);
1310112b52bSAndriy Gapon fprintf(stderr, "%s: updating cpu %s to revision %#x... ",
1320112b52bSAndriy Gapon path, dev, revision);
1330112b52bSAndriy Gapon
1340112b52bSAndriy Gapon args.data = __DECONST(void *, selected_fw);
1350112b52bSAndriy Gapon args.size = selected_size;
1360112b52bSAndriy Gapon error = ioctl(devfd, CPUCTL_UPDATE, &args);
1370112b52bSAndriy Gapon if (error < 0) {
1380112b52bSAndriy Gapon fprintf(stderr, "failed.\n");
1390112b52bSAndriy Gapon warn("ioctl()");
1400112b52bSAndriy Gapon goto done;
1410112b52bSAndriy Gapon }
1420112b52bSAndriy Gapon fprintf(stderr, "done.\n");
1430112b52bSAndriy Gapon }
1440112b52bSAndriy Gapon
145a18e40aaSMark Johnston msrargs.msr = MSR_BIOS_SIGN;
1460112b52bSAndriy Gapon error = ioctl(devfd, CPUCTL_RDMSR, &msrargs);
1470112b52bSAndriy Gapon if (error < 0) {
1480112b52bSAndriy Gapon WARN(0, "ioctl(%s)", dev);
1490112b52bSAndriy Gapon goto done;
1500112b52bSAndriy Gapon }
1510112b52bSAndriy Gapon new_rev = (uint32_t)msrargs.data;
1520112b52bSAndriy Gapon if (new_rev != revision)
1530112b52bSAndriy Gapon WARNX(0, "revision after update %#x", new_rev);
1540112b52bSAndriy Gapon
1550112b52bSAndriy Gapon done:
1560112b52bSAndriy Gapon return;
1570112b52bSAndriy Gapon }
158