1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/file.h>
29 #include <sys/errno.h>
30 #include <sys/open.h>
31 #include <sys/cred.h>
32 #include <sys/conf.h>
33 #include <sys/stat.h>
34 #include <sys/policy.h>
35 #include <sys/processor.h>
36 #include <sys/kmem.h>
37 #include <sys/modctl.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40
41 #include <sys/auxv.h>
42 #include <sys/ucode.h>
43 #include <sys/systeminfo.h>
44 #include <sys/x86_archext.h>
45
46 static dev_info_t *ucode_devi;
47 static uint32_t ucode_max_combined_size;
48 static kmutex_t ucode_update_lock;
49
50 /*ARGSUSED*/
51 static int
ucode_getinfo(dev_info_t * devi,ddi_info_cmd_t cmd,void * arg,void ** result)52 ucode_getinfo(dev_info_t *devi, ddi_info_cmd_t cmd, void *arg, void **result)
53 {
54 switch (cmd) {
55 case DDI_INFO_DEVT2DEVINFO:
56 case DDI_INFO_DEVT2INSTANCE:
57 break;
58 default:
59 return (DDI_FAILURE);
60 }
61
62 switch (getminor((dev_t)arg)) {
63 case UCODE_MINOR:
64 break;
65 default:
66 return (DDI_FAILURE);
67 }
68
69 if (cmd == DDI_INFO_DEVT2INSTANCE)
70 *result = 0;
71 else
72 *result = ucode_devi;
73 return (DDI_SUCCESS);
74 }
75
76 static int
ucode_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)77 ucode_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
78 {
79 ASSERT(cmd != DDI_RESUME);
80
81 switch (cmd) {
82 case DDI_RESUME:
83 return (DDI_SUCCESS);
84
85 case DDI_ATTACH:
86 ucode_devi = devi;
87 ucode_max_combined_size = UCODE_MAX_COMBINED_SIZE;
88
89 if (ddi_create_minor_node(devi, UCODE_NODE_NAME, S_IFCHR,
90 UCODE_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS) {
91 cmn_err(CE_WARN, "%s: Unable to create minor node",
92 UCODE_NODE_NAME);
93 return (DDI_FAILURE);
94 }
95 ddi_report_dev(devi);
96 return (DDI_SUCCESS);
97
98 default:
99 return (DDI_FAILURE);
100 }
101 }
102
103 static int
ucode_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)104 ucode_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
105 {
106 /*
107 * The power management and DR framework should never invoke this
108 * driver with DDI_SUSPEND because the ucode pseudo device does not
109 * have a reg property or hardware binding. However, we will return
110 * DDI_SUCCESS so that in the unlikely event that it does get
111 * called, the system will still suspend and resume.
112 */
113 ASSERT(cmd != DDI_SUSPEND);
114
115 switch (cmd) {
116 case DDI_SUSPEND:
117 return (DDI_SUCCESS);
118
119 case DDI_DETACH:
120 ddi_remove_minor_node(devi, NULL);
121 ucode_devi = NULL;
122 return (DDI_SUCCESS);
123
124 default:
125 return (DDI_FAILURE);
126 }
127 }
128
129 /*ARGSUSED1*/
130 static int
ucode_open(dev_t * dev,int flag,int otyp,cred_t * cr)131 ucode_open(dev_t *dev, int flag, int otyp, cred_t *cr)
132 {
133 return (getminor(*dev) == UCODE_MINOR ? 0 : ENXIO);
134 }
135
136
137 /*ARGSUSED*/
138 static int
ucode_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)139 ucode_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval)
140 {
141 /*
142 * Make sure that the ucode ops pointer has been set up.
143 */
144 if (!ucode)
145 return (EIO);
146
147 switch (cmd) {
148 case UCODE_GET_VERSION: {
149 int size;
150 uint32_t *revp, *rev_array;
151 size_t bufsz = NCPU * sizeof (*revp);
152 ucode_errno_t rc = EM_OK;
153
154 STRUCT_DECL(ucode_get_rev_struct, h);
155 STRUCT_INIT(h, mode);
156 if (ddi_copyin((void *)arg,
157 STRUCT_BUF(h), STRUCT_SIZE(h), mode))
158 return (EFAULT);
159
160 if ((size = STRUCT_FGET(h, ugv_size)) > NCPU || size < 0)
161 return (EINVAL);
162
163 if (size == 0)
164 return (0);
165
166 if ((rev_array = STRUCT_FGETP(h, ugv_rev)) == NULL)
167 return (EINVAL);
168
169 size *= sizeof (uint32_t);
170
171 /* Can't rely on caller for kernel's buffer size. */
172 revp = kmem_zalloc(bufsz, KM_SLEEP);
173 if (ddi_copyin((void *)rev_array, revp, size, mode) != 0) {
174 kmem_free(revp, bufsz);
175 return (EINVAL);
176 }
177
178 rc = ucode_get_rev(revp);
179
180 STRUCT_FSET(h, ugv_errno, rc);
181
182 if (ddi_copyout(revp, (void *)rev_array, size, mode) != 0) {
183 kmem_free(revp, bufsz);
184 return (EFAULT);
185 }
186
187 kmem_free(revp, bufsz);
188
189 if (ddi_copyout(STRUCT_BUF(h), (void *)arg,
190 STRUCT_SIZE(h), mode))
191 return (EFAULT);
192
193 return (0);
194 }
195
196 case UCODE_UPDATE: {
197 int size;
198 uint8_t *ucodep, *uw_ucode;
199 ucode_errno_t rc = EM_OK;
200
201 /*
202 * Requires all privilege.
203 */
204 if (cr && secpolicy_ucode_update(cr))
205 return (EPERM);
206
207 STRUCT_DECL(ucode_write_struct, h);
208
209 STRUCT_INIT(h, mode);
210 if (ddi_copyin((void *)arg, STRUCT_BUF(h), STRUCT_SIZE(h),
211 mode))
212 return (EFAULT);
213
214 /*
215 * We allow the size of the combined microcode file to be up to
216 * ucode_max_combined_size. It is initialized to
217 * UCODE_MAX_COMBINED_SIZE, and can be patched if necessary.
218 */
219 size = STRUCT_FGET(h, uw_size);
220 if (size > ucode_max_combined_size || size == 0)
221 return (EINVAL);
222
223 if ((uw_ucode = STRUCT_FGETP(h, uw_ucode)) == NULL)
224 return (EINVAL);
225
226 ucodep = kmem_zalloc(size, KM_SLEEP);
227 if (ddi_copyin((void *)uw_ucode, ucodep, size, mode) != 0) {
228 kmem_free(ucodep, size);
229 return (EFAULT);
230 }
231
232 if ((rc = ucode->validate(ucodep, size)) != EM_OK) {
233 kmem_free(ucodep, size);
234 STRUCT_FSET(h, uw_errno, rc);
235 if (ddi_copyout(STRUCT_BUF(h), (void *)arg,
236 STRUCT_SIZE(h), mode))
237 return (EFAULT);
238 return (0);
239 }
240
241 mutex_enter(&ucode_update_lock);
242 rc = ucode_update(ucodep, size);
243 mutex_exit(&ucode_update_lock);
244
245 kmem_free(ucodep, size);
246
247 STRUCT_FSET(h, uw_errno, rc);
248 if (ddi_copyout(STRUCT_BUF(h), (void *)arg,
249 STRUCT_SIZE(h), mode))
250 return (EFAULT);
251
252 /*
253 * Even if rc is not EM_OK, it is a successful operation
254 * from ioctl()'s perspective. We return the detailed error
255 * code via the ucode_write_struct data structure.
256 */
257 return (0);
258 }
259
260
261 default:
262 return (ENOTTY);
263 }
264 }
265
266 static struct cb_ops ucode_cb_ops = {
267 ucode_open,
268 nulldev, /* close */
269 nodev, /* strategy */
270 nodev, /* print */
271 nodev, /* dump */
272 nodev, /* read */
273 nodev, /* write */
274 ucode_ioctl,
275 nodev, /* devmap */
276 nodev, /* mmap */
277 nodev, /* segmap */
278 nochpoll, /* poll */
279 ddi_prop_op,
280 NULL,
281 D_64BIT | D_NEW | D_MP
282 };
283
284 static struct dev_ops ucode_dv_ops = {
285 DEVO_REV,
286 0,
287 ucode_getinfo,
288 nulldev, /* identify */
289 nulldev, /* probe */
290 ucode_attach,
291 ucode_detach,
292 nodev, /* reset */
293 &ucode_cb_ops,
294 (struct bus_ops *)0,
295 NULL, /* power */
296 ddi_quiesce_not_needed, /* quiesce */
297 };
298
299 static struct modldrv modldrv = {
300 &mod_driverops,
301 "ucode driver",
302 &ucode_dv_ops
303 };
304
305 static struct modlinkage modl = {
306 MODREV_1,
307 &modldrv
308 };
309
310 int
_init(void)311 _init(void)
312 {
313 int rc;
314
315 if ((rc = mod_install(&modl)) != 0)
316 return (rc);
317
318 mutex_init(&ucode_update_lock, NULL, MUTEX_DRIVER, NULL);
319
320 return (0);
321 }
322
323 int
_fini(void)324 _fini(void)
325 {
326 int rc;
327
328 if ((rc = mod_remove(&modl)) != 0)
329 return (rc);
330
331 mutex_destroy(&ucode_update_lock);
332
333 return (0);
334 }
335
336 int
_info(struct modinfo * modinfo)337 _info(struct modinfo *modinfo)
338 {
339 return (mod_info(&modl, modinfo));
340 }
341