xref: /freebsd/usr.sbin/cpucontrol/via.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
196ff3b75SFabien Thomas /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
496ff3b75SFabien Thomas  * Copyright (c) 2011 Fabien Thomas <fabient@FreeBSD.org>.
596ff3b75SFabien Thomas  * All rights reserved.
696ff3b75SFabien Thomas  *
796ff3b75SFabien Thomas  * Redistribution and use in source and binary forms, with or without
896ff3b75SFabien Thomas  * modification, are permitted provided that the following conditions
996ff3b75SFabien Thomas  * are met:
1096ff3b75SFabien Thomas  * 1. Redistributions of source code must retain the above copyright
1196ff3b75SFabien Thomas  *    notice, this list of conditions and the following disclaimer.
1296ff3b75SFabien Thomas  * 2. Redistributions in binary form must reproduce the above copyright
1396ff3b75SFabien Thomas  *    notice, this list of conditions and the following disclaimer in the
1496ff3b75SFabien Thomas  *    documentation and/or other materials provided with the distribution.
1596ff3b75SFabien Thomas  *
1696ff3b75SFabien Thomas  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1796ff3b75SFabien Thomas  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1896ff3b75SFabien Thomas  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1996ff3b75SFabien Thomas  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2096ff3b75SFabien Thomas  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2196ff3b75SFabien Thomas  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2296ff3b75SFabien Thomas  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2396ff3b75SFabien Thomas  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2496ff3b75SFabien Thomas  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2596ff3b75SFabien Thomas  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2696ff3b75SFabien Thomas  */
2796ff3b75SFabien Thomas 
2896ff3b75SFabien Thomas #include <sys/cdefs.h>
2996ff3b75SFabien Thomas #include <assert.h>
3096ff3b75SFabien Thomas #include <stdio.h>
3196ff3b75SFabien Thomas #include <stdlib.h>
3296ff3b75SFabien Thomas #include <string.h>
3396ff3b75SFabien Thomas #include <unistd.h>
3496ff3b75SFabien Thomas #include <fcntl.h>
3596ff3b75SFabien Thomas #include <err.h>
36bab89cefSEitan Adler #include <errno.h>
3796ff3b75SFabien Thomas 
3896ff3b75SFabien Thomas #include <sys/types.h>
3996ff3b75SFabien Thomas #include <sys/stat.h>
4096ff3b75SFabien Thomas #include <sys/mman.h>
4196ff3b75SFabien Thomas #include <sys/ioctl.h>
4296ff3b75SFabien Thomas #include <sys/ioccom.h>
4396ff3b75SFabien Thomas #include <sys/cpuctl.h>
4496ff3b75SFabien Thomas 
4596ff3b75SFabien Thomas #include <machine/cpufunc.h>
4696ff3b75SFabien Thomas #include <machine/specialreg.h>
4796ff3b75SFabien Thomas 
4896ff3b75SFabien Thomas #include "cpucontrol.h"
4996ff3b75SFabien Thomas #include "via.h"
5096ff3b75SFabien Thomas 
5196ff3b75SFabien Thomas int
via_probe(int fd)5296ff3b75SFabien Thomas via_probe(int fd)
5396ff3b75SFabien Thomas {
5496ff3b75SFabien Thomas 	char vendor[13];
5596ff3b75SFabien Thomas 	int error;
5696ff3b75SFabien Thomas 	cpuctl_cpuid_args_t idargs = {
5796ff3b75SFabien Thomas 		.level  = 0,
5896ff3b75SFabien Thomas 	};
5996ff3b75SFabien Thomas 
6096ff3b75SFabien Thomas 	error = ioctl(fd, CPUCTL_CPUID, &idargs);
6196ff3b75SFabien Thomas 	if (error < 0) {
6296ff3b75SFabien Thomas 		WARN(0, "ioctl()");
6396ff3b75SFabien Thomas 		return (1);
6496ff3b75SFabien Thomas 	}
6596ff3b75SFabien Thomas 	((uint32_t *)vendor)[0] = idargs.data[1];
6696ff3b75SFabien Thomas 	((uint32_t *)vendor)[1] = idargs.data[3];
6796ff3b75SFabien Thomas 	((uint32_t *)vendor)[2] = idargs.data[2];
6896ff3b75SFabien Thomas 	vendor[12] = '\0';
6996ff3b75SFabien Thomas 	if (strncmp(vendor, CENTAUR_VENDOR_ID, sizeof(CENTAUR_VENDOR_ID)) != 0)
7096ff3b75SFabien Thomas 		return (1);
7196ff3b75SFabien Thomas 
7296ff3b75SFabien Thomas 	/* TODO: detect Nano CPU. */
7396ff3b75SFabien Thomas 	return (0);
7496ff3b75SFabien Thomas }
7596ff3b75SFabien Thomas 
7696ff3b75SFabien Thomas void
via_update(const struct ucode_update_params * params)77dee401e8SConrad Meyer via_update(const struct ucode_update_params *params)
7896ff3b75SFabien Thomas {
79dee401e8SConrad Meyer 	int devfd;
80dee401e8SConrad Meyer 	const char *dev, *path;
81dee401e8SConrad Meyer 	const uint32_t *fw_image;
8296ff3b75SFabien Thomas 	uint32_t sum;
8396ff3b75SFabien Thomas 	unsigned int i;
8496ff3b75SFabien Thomas 	size_t payload_size;
85dee401e8SConrad Meyer 	const via_fw_header_t *fw_header;
86de879bdaSEitan Adler 	uint32_t signature;
8796ff3b75SFabien Thomas 	int32_t revision;
88dee401e8SConrad Meyer 	const void *fw_data;
8996ff3b75SFabien Thomas 	size_t data_size, total_size;
9096ff3b75SFabien Thomas 	cpuctl_msr_args_t msrargs = {
9196ff3b75SFabien Thomas 		.msr = MSR_IA32_PLATFORM_ID,
9296ff3b75SFabien Thomas 	};
9396ff3b75SFabien Thomas 	cpuctl_cpuid_args_t idargs = {
9496ff3b75SFabien Thomas 		.level  = 1,	/* Signature. */
9596ff3b75SFabien Thomas 	};
9696ff3b75SFabien Thomas 	cpuctl_update_args_t args;
9796ff3b75SFabien Thomas 	int error;
9896ff3b75SFabien Thomas 
99dee401e8SConrad Meyer 	dev = params->dev_path;
100dee401e8SConrad Meyer 	path = params->fw_path;
101dee401e8SConrad Meyer 	devfd = params->devfd;
102dee401e8SConrad Meyer 	fw_image = params->fwimage;
103dee401e8SConrad Meyer 
10496ff3b75SFabien Thomas 	assert(path);
10596ff3b75SFabien Thomas 	assert(dev);
10696ff3b75SFabien Thomas 
10796ff3b75SFabien Thomas 	error = ioctl(devfd, CPUCTL_CPUID, &idargs);
10896ff3b75SFabien Thomas 	if (error < 0) {
10996ff3b75SFabien Thomas 		WARN(0, "ioctl(%s)", dev);
11096ff3b75SFabien Thomas 		goto fail;
11196ff3b75SFabien Thomas 	}
11296ff3b75SFabien Thomas 	signature = idargs.data[0];
11396ff3b75SFabien Thomas 	error = ioctl(devfd, CPUCTL_RDMSR, &msrargs);
11496ff3b75SFabien Thomas 	if (error < 0) {
11596ff3b75SFabien Thomas 		WARN(0, "ioctl(%s)", dev);
11696ff3b75SFabien Thomas 		goto fail;
11796ff3b75SFabien Thomas 	}
11896ff3b75SFabien Thomas 
11996ff3b75SFabien Thomas 	/*
12096ff3b75SFabien Thomas 	 * MSR_IA32_PLATFORM_ID contains flag in BCD in bits 52-50.
12196ff3b75SFabien Thomas 	 */
12296ff3b75SFabien Thomas 	msrargs.msr = MSR_BIOS_SIGN;
12396ff3b75SFabien Thomas 	error = ioctl(devfd, CPUCTL_RDMSR, &msrargs);
12496ff3b75SFabien Thomas 	if (error < 0) {
12596ff3b75SFabien Thomas 		WARN(0, "ioctl(%s)", dev);
12696ff3b75SFabien Thomas 		goto fail;
12796ff3b75SFabien Thomas 	}
12896ff3b75SFabien Thomas 	revision = msrargs.data >> 32; /* Revision in the high dword. */
12996ff3b75SFabien Thomas 	WARNX(2, "found cpu type %#x family %#x model %#x stepping %#x.",
13096ff3b75SFabien Thomas 	    (signature >> 12) & 0x03, (signature >> 8) & 0x0f,
13196ff3b75SFabien Thomas 	    (signature >> 4) & 0x0f, (signature >> 0) & 0x0f);
132dee401e8SConrad Meyer 
133dee401e8SConrad Meyer 	if (params->fwsize < sizeof(*fw_header)) {
13496ff3b75SFabien Thomas 		WARNX(2, "file too short: %s", path);
13596ff3b75SFabien Thomas 		goto fail;
13696ff3b75SFabien Thomas 	}
13796ff3b75SFabien Thomas 
138dee401e8SConrad Meyer 	fw_header = (const via_fw_header_t *)fw_image;
13996ff3b75SFabien Thomas 	if (fw_header->signature != VIA_HEADER_SIGNATURE ||
14096ff3b75SFabien Thomas 	    fw_header->loader_revision != VIA_LOADER_REVISION) {
14196ff3b75SFabien Thomas 		WARNX(2, "%s is not a valid via firmware: version mismatch",
14296ff3b75SFabien Thomas 		    path);
14396ff3b75SFabien Thomas 		goto fail;
14496ff3b75SFabien Thomas 	}
14596ff3b75SFabien Thomas 	data_size = fw_header->data_size;
14696ff3b75SFabien Thomas 	total_size = fw_header->total_size;
147dee401e8SConrad Meyer 	if (total_size > params->fwsize) {
14896ff3b75SFabien Thomas 		WARNX(2, "file too short: %s", path);
14996ff3b75SFabien Thomas 		goto fail;
15096ff3b75SFabien Thomas 	}
15196ff3b75SFabien Thomas 	payload_size = data_size + sizeof(*fw_header);
15296ff3b75SFabien Thomas 
15396ff3b75SFabien Thomas 	/*
15496ff3b75SFabien Thomas 	 * Check the primary checksum.
15596ff3b75SFabien Thomas 	 */
15696ff3b75SFabien Thomas 	sum = 0;
15796ff3b75SFabien Thomas 	for (i = 0; i < (payload_size / sizeof(uint32_t)); i++)
158dee401e8SConrad Meyer 		sum += *((const uint32_t *)fw_image + i);
15996ff3b75SFabien Thomas 	if (sum != 0) {
16096ff3b75SFabien Thomas 		WARNX(2, "%s: update data checksum invalid", path);
16196ff3b75SFabien Thomas 		goto fail;
16296ff3b75SFabien Thomas 	}
16396ff3b75SFabien Thomas 
16496ff3b75SFabien Thomas 	fw_data = fw_header + 1; /* Pointer to the update data. */
16596ff3b75SFabien Thomas 
16696ff3b75SFabien Thomas 	/*
16796ff3b75SFabien Thomas 	 * Check if the given image is ok for this cpu.
16896ff3b75SFabien Thomas 	 */
16996ff3b75SFabien Thomas 	if (signature != fw_header->cpu_signature)
17096ff3b75SFabien Thomas 		goto fail;
17196ff3b75SFabien Thomas 
17296ff3b75SFabien Thomas 	if (fw_header->revision != 0 && revision >= fw_header->revision) {
17396ff3b75SFabien Thomas 		WARNX(1, "skipping %s of rev %#x: up to date",
17496ff3b75SFabien Thomas 		    path, fw_header->revision);
17596ff3b75SFabien Thomas 		goto fail;
17696ff3b75SFabien Thomas 	}
17796ff3b75SFabien Thomas 	fprintf(stderr, "%s: updating cpu %s from rev %#x to rev %#x... ",
17896ff3b75SFabien Thomas 			path, dev, revision, fw_header->revision);
179dee401e8SConrad Meyer 	args.data = __DECONST(void *, fw_data);
18096ff3b75SFabien Thomas 	args.size = data_size;
18196ff3b75SFabien Thomas 	error = ioctl(devfd, CPUCTL_UPDATE, &args);
18296ff3b75SFabien Thomas 	if (error < 0) {
183bab89cefSEitan Adler                error = errno;
18496ff3b75SFabien Thomas 	       fprintf(stderr, "failed.\n");
185bab89cefSEitan Adler                errno = error;
18696ff3b75SFabien Thomas 	       WARN(0, "ioctl()");
18796ff3b75SFabien Thomas 	       goto fail;
18896ff3b75SFabien Thomas 	}
18996ff3b75SFabien Thomas 	fprintf(stderr, "done.\n");
19096ff3b75SFabien Thomas 
19196ff3b75SFabien Thomas fail:
19296ff3b75SFabien Thomas 	return;
19396ff3b75SFabien Thomas }
194