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