1e085f869SStanislav Sedov /*- 21de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 31de7b4b8SPedro F. Giffuni * 4e085f869SStanislav Sedov * Copyright (c) 2006, 2008 Stanislav Sedov <stas@FreeBSD.org>. 5e085f869SStanislav Sedov * All rights reserved. 6e085f869SStanislav Sedov * 7e085f869SStanislav Sedov * Redistribution and use in source and binary forms, with or without 8e085f869SStanislav Sedov * modification, are permitted provided that the following conditions 9e085f869SStanislav Sedov * are met: 10e085f869SStanislav Sedov * 1. Redistributions of source code must retain the above copyright 11e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer. 12e085f869SStanislav Sedov * 2. Redistributions in binary form must reproduce the above copyright 13e085f869SStanislav Sedov * notice, this list of conditions and the following disclaimer in the 14e085f869SStanislav Sedov * documentation and/or other materials provided with the distribution. 15e085f869SStanislav Sedov * 16e085f869SStanislav Sedov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17e085f869SStanislav Sedov * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18e085f869SStanislav Sedov * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19e085f869SStanislav Sedov * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20e085f869SStanislav Sedov * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21e085f869SStanislav Sedov * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22e085f869SStanislav Sedov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23e085f869SStanislav Sedov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24e085f869SStanislav Sedov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25e085f869SStanislav Sedov * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26e085f869SStanislav Sedov */ 27e085f869SStanislav Sedov 28e085f869SStanislav Sedov #include <sys/cdefs.h> 29e085f869SStanislav Sedov __FBSDID("$FreeBSD$"); 30e085f869SStanislav Sedov 31e085f869SStanislav Sedov #include <assert.h> 32e085f869SStanislav Sedov #include <stdio.h> 33e085f869SStanislav Sedov #include <stdlib.h> 34e085f869SStanislav Sedov #include <string.h> 35e085f869SStanislav Sedov #include <unistd.h> 36e085f869SStanislav Sedov #include <fcntl.h> 37e085f869SStanislav Sedov #include <err.h> 38e085f869SStanislav Sedov 39e085f869SStanislav Sedov #include <sys/types.h> 40e085f869SStanislav Sedov #include <sys/stat.h> 41e085f869SStanislav Sedov #include <sys/mman.h> 42e085f869SStanislav Sedov #include <sys/ioctl.h> 43e085f869SStanislav Sedov #include <sys/ioccom.h> 44e085f869SStanislav Sedov #include <sys/cpuctl.h> 45e085f869SStanislav Sedov 46e085f869SStanislav Sedov #include <machine/cpufunc.h> 47e085f869SStanislav Sedov #include <machine/specialreg.h> 48e085f869SStanislav Sedov 49e085f869SStanislav Sedov #include "cpucontrol.h" 50e085f869SStanislav Sedov #include "amd.h" 51e085f869SStanislav Sedov 52e085f869SStanislav Sedov int 53e085f869SStanislav Sedov amd_probe(int fd) 54e085f869SStanislav Sedov { 55e085f869SStanislav Sedov char vendor[13]; 56e085f869SStanislav Sedov int error; 57e085f869SStanislav Sedov cpuctl_cpuid_args_t idargs = { 58e085f869SStanislav Sedov .level = 0, 59e085f869SStanislav Sedov }; 60e085f869SStanislav Sedov 61e085f869SStanislav Sedov error = ioctl(fd, CPUCTL_CPUID, &idargs); 62e085f869SStanislav Sedov if (error < 0) { 63e085f869SStanislav Sedov WARN(0, "ioctl()"); 64e085f869SStanislav Sedov return (1); 65e085f869SStanislav Sedov } 66e085f869SStanislav Sedov ((uint32_t *)vendor)[0] = idargs.data[1]; 67e085f869SStanislav Sedov ((uint32_t *)vendor)[1] = idargs.data[3]; 68e085f869SStanislav Sedov ((uint32_t *)vendor)[2] = idargs.data[2]; 69e085f869SStanislav Sedov vendor[12] = '\0'; 70e085f869SStanislav Sedov if (strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) != 0) 71e085f869SStanislav Sedov return (1); 72e085f869SStanislav Sedov return (0); 73e085f869SStanislav Sedov } 74e085f869SStanislav Sedov 75e085f869SStanislav Sedov void 76*dee401e8SConrad Meyer amd_update(const struct ucode_update_params *params) 77e085f869SStanislav Sedov { 78*dee401e8SConrad Meyer int devfd; 79e085f869SStanislav Sedov unsigned int i; 80*dee401e8SConrad Meyer const char *dev, *path; 81*dee401e8SConrad Meyer const uint32_t *fw_image; 82*dee401e8SConrad Meyer const amd_fw_header_t *fw_header; 83e085f869SStanislav Sedov uint32_t sum; 84e085f869SStanislav Sedov uint32_t signature; 85*dee401e8SConrad Meyer const uint32_t *fw_data; 86e085f869SStanislav Sedov size_t fw_size; 87e085f869SStanislav Sedov cpuctl_cpuid_args_t idargs = { 88e085f869SStanislav Sedov .level = 1, /* Request signature. */ 89e085f869SStanislav Sedov }; 90e085f869SStanislav Sedov cpuctl_update_args_t args; 91e085f869SStanislav Sedov int error; 92e085f869SStanislav Sedov 93*dee401e8SConrad Meyer dev = params->dev_path; 94*dee401e8SConrad Meyer path = params->fw_path; 95*dee401e8SConrad Meyer devfd = params->devfd; 96*dee401e8SConrad Meyer fw_image = params->fwimage; 97*dee401e8SConrad Meyer 98e085f869SStanislav Sedov assert(path); 99e085f869SStanislav Sedov assert(dev); 100e085f869SStanislav Sedov 101e085f869SStanislav Sedov error = ioctl(devfd, CPUCTL_CPUID, &idargs); 102e085f869SStanislav Sedov if (error < 0) { 103e085f869SStanislav Sedov WARN(0, "ioctl()"); 104e085f869SStanislav Sedov goto fail; 105e085f869SStanislav Sedov } 106e085f869SStanislav Sedov signature = idargs.data[0]; 107e085f869SStanislav Sedov WARNX(2, "found cpu family %#x model %#x " 108e085f869SStanislav Sedov "stepping %#x extfamily %#x extmodel %#x.", 109e085f869SStanislav Sedov (signature >> 8) & 0x0f, (signature >> 4) & 0x0f, 110e085f869SStanislav Sedov (signature >> 0) & 0x0f, (signature >> 20) & 0xff, 111e085f869SStanislav Sedov (signature >> 16) & 0x0f); 112e085f869SStanislav Sedov 113e085f869SStanislav Sedov /* 114e085f869SStanislav Sedov * Open the firmware file. 115e085f869SStanislav Sedov */ 116*dee401e8SConrad Meyer if (params->fwsize < sizeof(*fw_header)) { 117e085f869SStanislav Sedov WARNX(2, "file too short: %s", path); 118e085f869SStanislav Sedov goto fail; 119e085f869SStanislav Sedov } 120*dee401e8SConrad Meyer fw_header = (const amd_fw_header_t *)fw_image; 121e085f869SStanislav Sedov if ((fw_header->magic >> 8) != AMD_MAGIC) { 122e085f869SStanislav Sedov WARNX(2, "%s is not a valid amd firmware: version mismatch", 123e085f869SStanislav Sedov path); 124e085f869SStanislav Sedov goto fail; 125e085f869SStanislav Sedov } 126*dee401e8SConrad Meyer fw_data = (const uint32_t *)(fw_header + 1); 127*dee401e8SConrad Meyer fw_size = (params->fwsize - sizeof(*fw_header)) / sizeof(uint32_t); 128e085f869SStanislav Sedov 129e085f869SStanislav Sedov /* 130e085f869SStanislav Sedov * Check the primary checksum. 131e085f869SStanislav Sedov */ 132e085f869SStanislav Sedov sum = 0; 133e085f869SStanislav Sedov for (i = 0; i < fw_size; i++) 134e085f869SStanislav Sedov sum += fw_data[i]; 135e085f869SStanislav Sedov if (sum != fw_header->checksum) { 136e085f869SStanislav Sedov WARNX(2, "%s: update data checksum invalid", path); 137e085f869SStanislav Sedov goto fail; 138e085f869SStanislav Sedov } 139e085f869SStanislav Sedov if (signature == fw_header->signature) { 140e085f869SStanislav Sedov fprintf(stderr, "%s: updating cpu %s... ", path, dev); 141e085f869SStanislav Sedov 142*dee401e8SConrad Meyer args.data = __DECONST(void *, fw_image); 143*dee401e8SConrad Meyer args.size = params->fwsize; 1444ced504bSAndriy Gapon error = ioctl(devfd, CPUCTL_UPDATE, &args); 145e085f869SStanislav Sedov if (error < 0) { 146e085f869SStanislav Sedov fprintf(stderr, "failed.\n"); 147e085f869SStanislav Sedov warn("ioctl()"); 148e085f869SStanislav Sedov goto fail; 149e085f869SStanislav Sedov } 150e085f869SStanislav Sedov fprintf(stderr, "done.\n"); 151e085f869SStanislav Sedov } 152e085f869SStanislav Sedov 153e085f869SStanislav Sedov fail: 154e085f869SStanislav Sedov return; 155e085f869SStanislav Sedov } 156