cpuctl.c revision 315969
1181430Sstas/*- 2181430Sstas * Copyright (c) 2006-2008 Stanislav Sedov <stas@FreeBSD.org> 3181430Sstas * All rights reserved. 4181430Sstas * 5181430Sstas * Redistribution and use in source and binary forms, with or without 6181430Sstas * modification, are permitted provided that the following conditions 7181430Sstas * are met: 8181430Sstas * 1. Redistributions of source code must retain the above copyright 9181430Sstas * notice, this list of conditions and the following disclaimer. 10181430Sstas * 2. Redistributions in binary form must reproduce the above copyright 11181430Sstas * notice, this list of conditions and the following disclaimer in the 12181430Sstas * documentation and/or other materials provided with the distribution. 13181430Sstas * 14181430Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15181430Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16181430Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17181430Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18181430Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19181430Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20181430Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21181430Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22181430Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23181430Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24181430Sstas * SUCH DAMAGE. 25181430Sstas * 26181430Sstas */ 27181430Sstas 28181430Sstas#include <sys/cdefs.h> 29181430Sstas__FBSDID("$FreeBSD: stable/11/sys/dev/cpuctl/cpuctl.c 315969 2017-03-26 00:53:34Z kib $"); 30181430Sstas 31181430Sstas#include <sys/param.h> 32181430Sstas#include <sys/systm.h> 33181430Sstas#include <sys/conf.h> 34181430Sstas#include <sys/fcntl.h> 35181430Sstas#include <sys/ioccom.h> 36181430Sstas#include <sys/malloc.h> 37181430Sstas#include <sys/module.h> 38181430Sstas#include <sys/mutex.h> 39181430Sstas#include <sys/priv.h> 40181430Sstas#include <sys/proc.h> 41181430Sstas#include <sys/queue.h> 42181430Sstas#include <sys/sched.h> 43181430Sstas#include <sys/kernel.h> 44181430Sstas#include <sys/sysctl.h> 45181430Sstas#include <sys/uio.h> 46181430Sstas#include <sys/pcpu.h> 47181430Sstas#include <sys/smp.h> 48181430Sstas#include <sys/pmckern.h> 49181430Sstas#include <sys/cpuctl.h> 50181430Sstas 51181430Sstas#include <machine/cpufunc.h> 52181430Sstas#include <machine/md_var.h> 53181430Sstas#include <machine/specialreg.h> 54181430Sstas 55181430Sstasstatic d_open_t cpuctl_open; 56181430Sstasstatic d_ioctl_t cpuctl_ioctl; 57181430Sstas 58181430Sstas#define CPUCTL_VERSION 1 59181430Sstas 60308481Savg#ifdef CPUCTL_DEBUG 61181430Sstas# define DPRINTF(format,...) printf(format, __VA_ARGS__); 62181430Sstas#else 63181430Sstas# define DPRINTF(...) 64181430Sstas#endif 65181430Sstas 66308801Skib#define UCODE_SIZE_MAX (4 * 1024 * 1024) 67181430Sstas 68181430Sstasstatic int cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, 69181430Sstas struct thread *td); 70301962Skibstatic int cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, 71181430Sstas struct thread *td); 72301962Skibstatic int cpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_count_args_t *data, 73267651Sattilio struct thread *td); 74181430Sstasstatic int cpuctl_do_update(int cpu, cpuctl_update_args_t *data, 75181430Sstas struct thread *td); 76181430Sstasstatic int update_intel(int cpu, cpuctl_update_args_t *args, 77181430Sstas struct thread *td); 78181430Sstasstatic int update_amd(int cpu, cpuctl_update_args_t *args, struct thread *td); 79228436Sfabientstatic int update_via(int cpu, cpuctl_update_args_t *args, 80228436Sfabient struct thread *td); 81181430Sstas 82181430Sstasstatic struct cdev **cpuctl_devs; 83181430Sstasstatic MALLOC_DEFINE(M_CPUCTL, "cpuctl", "CPUCTL buffer"); 84181430Sstas 85181430Sstasstatic struct cdevsw cpuctl_cdevsw = { 86181430Sstas .d_version = D_VERSION, 87181430Sstas .d_open = cpuctl_open, 88181430Sstas .d_ioctl = cpuctl_ioctl, 89181430Sstas .d_name = "cpuctl", 90181430Sstas}; 91181430Sstas 92181430Sstas/* 93181430Sstas * This function checks if specified cpu enabled or not. 94181430Sstas */ 95181430Sstasstatic int 96181430Sstascpu_enabled(int cpu) 97181430Sstas{ 98181430Sstas 99181430Sstas return (pmc_cpu_is_disabled(cpu) == 0); 100181430Sstas} 101181430Sstas 102181430Sstas/* 103181430Sstas * Check if the current thread is bound to a specific cpu. 104181430Sstas */ 105181430Sstasstatic int 106181430Sstascpu_sched_is_bound(struct thread *td) 107181430Sstas{ 108181430Sstas int ret; 109181430Sstas 110181430Sstas thread_lock(td); 111181430Sstas ret = sched_is_bound(td); 112181430Sstas thread_unlock(td); 113181430Sstas return (ret); 114181430Sstas} 115181430Sstas 116181430Sstas/* 117181430Sstas * Switch to target cpu to run. 118181430Sstas */ 119181430Sstasstatic void 120181430Sstasset_cpu(int cpu, struct thread *td) 121181430Sstas{ 122181430Sstas 123302372Snwhitehorn KASSERT(cpu >= 0 && cpu <= mp_maxid && cpu_enabled(cpu), 124181430Sstas ("[cpuctl,%d]: bad cpu number %d", __LINE__, cpu)); 125181430Sstas thread_lock(td); 126181430Sstas sched_bind(td, cpu); 127181430Sstas thread_unlock(td); 128181430Sstas KASSERT(td->td_oncpu == cpu, 129315969Skib ("[cpuctl,%d]: cannot bind to target cpu %d on cpu %d", __LINE__, 130315969Skib cpu, td->td_oncpu)); 131181430Sstas} 132181430Sstas 133181430Sstasstatic void 134181430Sstasrestore_cpu(int oldcpu, int is_bound, struct thread *td) 135181430Sstas{ 136181430Sstas 137302372Snwhitehorn KASSERT(oldcpu >= 0 && oldcpu <= mp_maxid && cpu_enabled(oldcpu), 138181430Sstas ("[cpuctl,%d]: bad cpu number %d", __LINE__, oldcpu)); 139181430Sstas thread_lock(td); 140181430Sstas if (is_bound == 0) 141181430Sstas sched_unbind(td); 142181430Sstas else 143181430Sstas sched_bind(td, oldcpu); 144181430Sstas thread_unlock(td); 145181430Sstas} 146181430Sstas 147181430Sstasint 148181430Sstascpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 149315969Skib int flags, struct thread *td) 150181430Sstas{ 151315969Skib int cpu, ret; 152181430Sstas 153315969Skib cpu = dev2unit(dev); 154302372Snwhitehorn if (cpu > mp_maxid || !cpu_enabled(cpu)) { 155181430Sstas DPRINTF("[cpuctl,%d]: bad cpu number %d\n", __LINE__, cpu); 156181430Sstas return (ENXIO); 157181430Sstas } 158181430Sstas /* Require write flag for "write" requests. */ 159181430Sstas if ((cmd == CPUCTL_WRMSR || cmd == CPUCTL_UPDATE) && 160181430Sstas ((flags & FWRITE) == 0)) 161181430Sstas return (EPERM); 162181430Sstas switch (cmd) { 163181430Sstas case CPUCTL_RDMSR: 164181430Sstas ret = cpuctl_do_msr(cpu, (cpuctl_msr_args_t *)data, cmd, td); 165181430Sstas break; 166195189Sstas case CPUCTL_MSRSBIT: 167195189Sstas case CPUCTL_MSRCBIT: 168181430Sstas case CPUCTL_WRMSR: 169181430Sstas ret = priv_check(td, PRIV_CPUCTL_WRMSR); 170181430Sstas if (ret != 0) 171181430Sstas goto fail; 172181430Sstas ret = cpuctl_do_msr(cpu, (cpuctl_msr_args_t *)data, cmd, td); 173181430Sstas break; 174181430Sstas case CPUCTL_CPUID: 175301962Skib ret = cpuctl_do_cpuid(cpu, (cpuctl_cpuid_args_t *)data, td); 176181430Sstas break; 177181430Sstas case CPUCTL_UPDATE: 178181430Sstas ret = priv_check(td, PRIV_CPUCTL_UPDATE); 179181430Sstas if (ret != 0) 180181430Sstas goto fail; 181181430Sstas ret = cpuctl_do_update(cpu, (cpuctl_update_args_t *)data, td); 182181430Sstas break; 183267651Sattilio case CPUCTL_CPUID_COUNT: 184301962Skib ret = cpuctl_do_cpuid_count(cpu, 185301962Skib (cpuctl_cpuid_count_args_t *)data, td); 186267651Sattilio break; 187181430Sstas default: 188181430Sstas ret = EINVAL; 189181430Sstas break; 190181430Sstas } 191181430Sstasfail: 192181430Sstas return (ret); 193181430Sstas} 194181430Sstas 195181430Sstas/* 196181430Sstas * Actually perform cpuid operation. 197181430Sstas */ 198301962Skibstatic int 199267673Skibcpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_count_args_t *data, 200267673Skib struct thread *td) 201181430Sstas{ 202181430Sstas int is_bound = 0; 203181430Sstas int oldcpu; 204181430Sstas 205302372Snwhitehorn KASSERT(cpu >= 0 && cpu <= mp_maxid, 206181430Sstas ("[cpuctl,%d]: bad cpu number %d", __LINE__, cpu)); 207181430Sstas 208181430Sstas /* Explicitly clear cpuid data to avoid returning stale info. */ 209181430Sstas bzero(data->data, sizeof(data->data)); 210267651Sattilio DPRINTF("[cpuctl,%d]: retrieving cpuid lev %#0x type %#0x for %d cpu\n", 211267651Sattilio __LINE__, data->level, data->level_type, cpu); 212301962Skib#ifdef __i386__ 213301962Skib if (cpu_id == 0) 214301962Skib return (ENODEV); 215301962Skib#endif 216181430Sstas oldcpu = td->td_oncpu; 217181430Sstas is_bound = cpu_sched_is_bound(td); 218181430Sstas set_cpu(cpu, td); 219267651Sattilio cpuid_count(data->level, data->level_type, data->data); 220181430Sstas restore_cpu(oldcpu, is_bound, td); 221301962Skib return (0); 222181430Sstas} 223181430Sstas 224301962Skibstatic int 225267651Sattiliocpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) 226267651Sattilio{ 227267673Skib cpuctl_cpuid_count_args_t cdata; 228301962Skib int error; 229267651Sattilio 230267673Skib cdata.level = data->level; 231267651Sattilio /* Override the level type. */ 232267673Skib cdata.level_type = 0; 233301962Skib error = cpuctl_do_cpuid_count(cpu, &cdata, td); 234267673Skib bcopy(cdata.data, data->data, sizeof(data->data)); /* Ignore error */ 235301962Skib return (error); 236267651Sattilio} 237267651Sattilio 238181430Sstas/* 239181430Sstas * Actually perform MSR operations. 240181430Sstas */ 241181430Sstasstatic int 242181430Sstascpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, struct thread *td) 243181430Sstas{ 244195189Sstas uint64_t reg; 245181430Sstas int is_bound = 0; 246181430Sstas int oldcpu; 247181430Sstas int ret; 248181430Sstas 249302372Snwhitehorn KASSERT(cpu >= 0 && cpu <= mp_maxid, 250181430Sstas ("[cpuctl,%d]: bad cpu number %d", __LINE__, cpu)); 251181430Sstas 252181430Sstas /* 253181430Sstas * Explicitly clear cpuid data to avoid returning stale 254181430Sstas * info 255181430Sstas */ 256181430Sstas DPRINTF("[cpuctl,%d]: operating on MSR %#0x for %d cpu\n", __LINE__, 257181430Sstas data->msr, cpu); 258301962Skib#ifdef __i386__ 259301962Skib if ((cpu_feature & CPUID_MSR) == 0) 260301962Skib return (ENODEV); 261301962Skib#endif 262181430Sstas oldcpu = td->td_oncpu; 263181430Sstas is_bound = cpu_sched_is_bound(td); 264181430Sstas set_cpu(cpu, td); 265195081Sstas if (cmd == CPUCTL_RDMSR) { 266195081Sstas data->data = 0; 267195081Sstas ret = rdmsr_safe(data->msr, &data->data); 268195189Sstas } else if (cmd == CPUCTL_WRMSR) { 269195081Sstas ret = wrmsr_safe(data->msr, data->data); 270195189Sstas } else if (cmd == CPUCTL_MSRSBIT) { 271195189Sstas critical_enter(); 272195189Sstas ret = rdmsr_safe(data->msr, ®); 273195189Sstas if (ret == 0) 274195189Sstas ret = wrmsr_safe(data->msr, reg | data->data); 275195189Sstas critical_exit(); 276195189Sstas } else if (cmd == CPUCTL_MSRCBIT) { 277195189Sstas critical_enter(); 278195189Sstas ret = rdmsr_safe(data->msr, ®); 279195189Sstas if (ret == 0) 280195189Sstas ret = wrmsr_safe(data->msr, reg & ~data->data); 281195189Sstas critical_exit(); 282195189Sstas } else 283315969Skib panic("[cpuctl,%d]: unknown operation requested: %lu", 284315969Skib __LINE__, cmd); 285181430Sstas restore_cpu(oldcpu, is_bound, td); 286181430Sstas return (ret); 287181430Sstas} 288181430Sstas 289181430Sstas/* 290181430Sstas * Actually perform microcode update. 291181430Sstas */ 292181430Sstasstatic int 293181430Sstascpuctl_do_update(int cpu, cpuctl_update_args_t *data, struct thread *td) 294181430Sstas{ 295181430Sstas cpuctl_cpuid_args_t args = { 296181430Sstas .level = 0, 297181430Sstas }; 298181430Sstas char vendor[13]; 299181430Sstas int ret; 300181430Sstas 301302372Snwhitehorn KASSERT(cpu >= 0 && cpu <= mp_maxid, 302181430Sstas ("[cpuctl,%d]: bad cpu number %d", __LINE__, cpu)); 303181430Sstas DPRINTF("[cpuctl,%d]: XXX %d", __LINE__, cpu); 304181430Sstas 305301962Skib ret = cpuctl_do_cpuid(cpu, &args, td); 306301962Skib if (ret != 0) 307301962Skib return (ret); 308181430Sstas ((uint32_t *)vendor)[0] = args.data[1]; 309181430Sstas ((uint32_t *)vendor)[1] = args.data[3]; 310181430Sstas ((uint32_t *)vendor)[2] = args.data[2]; 311181430Sstas vendor[12] = '\0'; 312181430Sstas if (strncmp(vendor, INTEL_VENDOR_ID, sizeof(INTEL_VENDOR_ID)) == 0) 313181430Sstas ret = update_intel(cpu, data, td); 314228436Sfabient else if(strncmp(vendor, AMD_VENDOR_ID, sizeof(AMD_VENDOR_ID)) == 0) 315181430Sstas ret = update_amd(cpu, data, td); 316315969Skib else if(strncmp(vendor, CENTAUR_VENDOR_ID, sizeof(CENTAUR_VENDOR_ID)) 317315969Skib == 0) 318228436Sfabient ret = update_via(cpu, data, td); 319181430Sstas else 320181430Sstas ret = ENXIO; 321181430Sstas return (ret); 322181430Sstas} 323181430Sstas 324181430Sstasstatic int 325181430Sstasupdate_intel(int cpu, cpuctl_update_args_t *args, struct thread *td) 326181430Sstas{ 327255439Skib void *ptr; 328181430Sstas uint64_t rev0, rev1; 329181430Sstas uint32_t tmp[4]; 330255439Skib int is_bound; 331181430Sstas int oldcpu; 332181430Sstas int ret; 333181430Sstas 334181430Sstas if (args->size == 0 || args->data == NULL) { 335181430Sstas DPRINTF("[cpuctl,%d]: zero-sized firmware image", __LINE__); 336181430Sstas return (EINVAL); 337181430Sstas } 338181430Sstas if (args->size > UCODE_SIZE_MAX) { 339181430Sstas DPRINTF("[cpuctl,%d]: firmware image too large", __LINE__); 340181430Sstas return (EINVAL); 341181430Sstas } 342181430Sstas 343181430Sstas /* 344255439Skib * 16 byte alignment required. Rely on the fact that 345255439Skib * malloc(9) always returns the pointer aligned at least on 346255439Skib * the size of the allocation. 347181430Sstas */ 348181430Sstas ptr = malloc(args->size + 16, M_CPUCTL, M_WAITOK); 349181430Sstas if (copyin(args->data, ptr, args->size) != 0) { 350181430Sstas DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed", 351181430Sstas __LINE__, args->data, ptr, args->size); 352181430Sstas ret = EFAULT; 353181430Sstas goto fail; 354181430Sstas } 355181430Sstas oldcpu = td->td_oncpu; 356181430Sstas is_bound = cpu_sched_is_bound(td); 357181430Sstas set_cpu(cpu, td); 358181430Sstas critical_enter(); 359252592Srpaulo rdmsr_safe(MSR_BIOS_SIGN, &rev0); /* Get current microcode revision. */ 360181430Sstas 361181430Sstas /* 362181430Sstas * Perform update. 363181430Sstas */ 364181430Sstas wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uintptr_t)(ptr)); 365181430Sstas wrmsr_safe(MSR_BIOS_SIGN, 0); 366181430Sstas 367181430Sstas /* 368181430Sstas * Serialize instruction flow. 369181430Sstas */ 370181430Sstas do_cpuid(0, tmp); 371181430Sstas critical_exit(); 372252592Srpaulo rdmsr_safe(MSR_BIOS_SIGN, &rev1); /* Get new microcode revision. */ 373181430Sstas restore_cpu(oldcpu, is_bound, td); 374181430Sstas if (rev1 > rev0) 375181430Sstas ret = 0; 376181430Sstas else 377181430Sstas ret = EEXIST; 378181430Sstasfail: 379254191Skib free(ptr, M_CPUCTL); 380181430Sstas return (ret); 381181430Sstas} 382181430Sstas 383308760Savg/* 384308760Savg * NB: MSR 0xc0010020, MSR_K8_UCODE_UPDATE, is not documented by AMD. 385308760Savg * Coreboot, illumos and Linux source code was used to understand 386308760Savg * its workings. 387308760Savg */ 388308760Savgstatic void 389308760Savgamd_ucode_wrmsr(void *ucode_ptr) 390308760Savg{ 391308760Savg uint32_t tmp[4]; 392308760Savg 393308760Savg wrmsr_safe(MSR_K8_UCODE_UPDATE, (uintptr_t)ucode_ptr); 394308760Savg do_cpuid(0, tmp); 395308760Savg} 396308760Savg 397181430Sstasstatic int 398181430Sstasupdate_amd(int cpu, cpuctl_update_args_t *args, struct thread *td) 399181430Sstas{ 400308760Savg void *ptr; 401181430Sstas int ret; 402181430Sstas 403181430Sstas if (args->size == 0 || args->data == NULL) { 404181430Sstas DPRINTF("[cpuctl,%d]: zero-sized firmware image", __LINE__); 405181430Sstas return (EINVAL); 406181430Sstas } 407181430Sstas if (args->size > UCODE_SIZE_MAX) { 408181430Sstas DPRINTF("[cpuctl,%d]: firmware image too large", __LINE__); 409181430Sstas return (EINVAL); 410181430Sstas } 411308760Savg 412181430Sstas /* 413308760Savg * 16 byte alignment required. Rely on the fact that 414308760Savg * malloc(9) always returns the pointer aligned at least on 415308760Savg * the size of the allocation. 416181430Sstas */ 417308760Savg ptr = malloc(args->size + 16, M_CPUCTL, M_ZERO | M_WAITOK); 418181430Sstas if (copyin(args->data, ptr, args->size) != 0) { 419181430Sstas DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed", 420181430Sstas __LINE__, args->data, ptr, args->size); 421181430Sstas ret = EFAULT; 422181430Sstas goto fail; 423181430Sstas } 424308760Savg smp_rendezvous(NULL, amd_ucode_wrmsr, NULL, ptr); 425181430Sstas ret = 0; 426181430Sstasfail: 427308760Savg free(ptr, M_CPUCTL); 428181430Sstas return (ret); 429181430Sstas} 430181430Sstas 431228436Sfabientstatic int 432228436Sfabientupdate_via(int cpu, cpuctl_update_args_t *args, struct thread *td) 433228436Sfabient{ 434255439Skib void *ptr; 435228436Sfabient uint64_t rev0, rev1, res; 436228436Sfabient uint32_t tmp[4]; 437255439Skib int is_bound; 438228436Sfabient int oldcpu; 439228436Sfabient int ret; 440228436Sfabient 441228436Sfabient if (args->size == 0 || args->data == NULL) { 442228436Sfabient DPRINTF("[cpuctl,%d]: zero-sized firmware image", __LINE__); 443228436Sfabient return (EINVAL); 444228436Sfabient } 445228436Sfabient if (args->size > UCODE_SIZE_MAX) { 446228436Sfabient DPRINTF("[cpuctl,%d]: firmware image too large", __LINE__); 447228436Sfabient return (EINVAL); 448228436Sfabient } 449228436Sfabient 450228436Sfabient /* 451228436Sfabient * 4 byte alignment required. 452228436Sfabient */ 453255439Skib ptr = malloc(args->size, M_CPUCTL, M_WAITOK); 454228436Sfabient if (copyin(args->data, ptr, args->size) != 0) { 455228436Sfabient DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed", 456228436Sfabient __LINE__, args->data, ptr, args->size); 457228436Sfabient ret = EFAULT; 458228436Sfabient goto fail; 459228436Sfabient } 460228436Sfabient oldcpu = td->td_oncpu; 461228436Sfabient is_bound = cpu_sched_is_bound(td); 462228436Sfabient set_cpu(cpu, td); 463228436Sfabient critical_enter(); 464252592Srpaulo rdmsr_safe(MSR_BIOS_SIGN, &rev0); /* Get current microcode revision. */ 465228436Sfabient 466228436Sfabient /* 467228436Sfabient * Perform update. 468228436Sfabient */ 469228436Sfabient wrmsr_safe(MSR_BIOS_UPDT_TRIG, (uintptr_t)(ptr)); 470228436Sfabient do_cpuid(1, tmp); 471228436Sfabient 472228436Sfabient /* 473228436Sfabient * Result are in low byte of MSR FCR5: 474228436Sfabient * 0x00: No update has been attempted since RESET. 475228436Sfabient * 0x01: The last attempted update was successful. 476228436Sfabient * 0x02: The last attempted update was unsuccessful due to a bad 477228436Sfabient * environment. No update was loaded and any preexisting 478228436Sfabient * patches are still active. 479228436Sfabient * 0x03: The last attempted update was not applicable to this processor. 480228436Sfabient * No update was loaded and any preexisting patches are still 481228436Sfabient * active. 482228436Sfabient * 0x04: The last attempted update was not successful due to an invalid 483228436Sfabient * update data block. No update was loaded and any preexisting 484228436Sfabient * patches are still active 485228436Sfabient */ 486228436Sfabient rdmsr_safe(0x1205, &res); 487228436Sfabient res &= 0xff; 488228436Sfabient critical_exit(); 489228436Sfabient rdmsr_safe(MSR_BIOS_SIGN, &rev1); /* Get new microcode revision. */ 490228436Sfabient restore_cpu(oldcpu, is_bound, td); 491228436Sfabient 492228436Sfabient DPRINTF("[cpu,%d]: rev0=%x rev1=%x res=%x\n", __LINE__, 493228436Sfabient (unsigned)(rev0 >> 32), (unsigned)(rev1 >> 32), (unsigned)res); 494228436Sfabient 495228436Sfabient if (res != 0x01) 496228436Sfabient ret = EINVAL; 497228436Sfabient else 498228436Sfabient ret = 0; 499228436Sfabientfail: 500254191Skib free(ptr, M_CPUCTL); 501228436Sfabient return (ret); 502228436Sfabient} 503228436Sfabient 504181430Sstasint 505181430Sstascpuctl_open(struct cdev *dev, int flags, int fmt __unused, struct thread *td) 506181430Sstas{ 507181430Sstas int ret = 0; 508181430Sstas int cpu; 509181430Sstas 510183397Sed cpu = dev2unit(dev); 511302372Snwhitehorn if (cpu > mp_maxid || !cpu_enabled(cpu)) { 512181430Sstas DPRINTF("[cpuctl,%d]: incorrect cpu number %d\n", __LINE__, 513181430Sstas cpu); 514181430Sstas return (ENXIO); 515181430Sstas } 516181430Sstas if (flags & FWRITE) 517181430Sstas ret = securelevel_gt(td->td_ucred, 0); 518181430Sstas return (ret); 519181430Sstas} 520181430Sstas 521181430Sstasstatic int 522181430Sstascpuctl_modevent(module_t mod __unused, int type, void *data __unused) 523181430Sstas{ 524181430Sstas int cpu; 525181430Sstas 526181430Sstas switch(type) { 527181430Sstas case MOD_LOAD: 528181430Sstas if (bootverbose) 529181430Sstas printf("cpuctl: access to MSR registers/cpuid info.\n"); 530302372Snwhitehorn cpuctl_devs = malloc(sizeof(*cpuctl_devs) * (mp_maxid + 1), M_CPUCTL, 531263080Skib M_WAITOK | M_ZERO); 532302372Snwhitehorn CPU_FOREACH(cpu) 533181430Sstas if (cpu_enabled(cpu)) 534181430Sstas cpuctl_devs[cpu] = make_dev(&cpuctl_cdevsw, cpu, 535181430Sstas UID_ROOT, GID_KMEM, 0640, "cpuctl%d", cpu); 536181430Sstas break; 537181430Sstas case MOD_UNLOAD: 538302372Snwhitehorn CPU_FOREACH(cpu) { 539181430Sstas if (cpuctl_devs[cpu] != NULL) 540181430Sstas destroy_dev(cpuctl_devs[cpu]); 541181430Sstas } 542181430Sstas free(cpuctl_devs, M_CPUCTL); 543181430Sstas break; 544181430Sstas case MOD_SHUTDOWN: 545181430Sstas break; 546181430Sstas default: 547181430Sstas return (EOPNOTSUPP); 548181430Sstas } 549181430Sstas return (0); 550181430Sstas} 551181430Sstas 552181430SstasDEV_MODULE(cpuctl, cpuctl_modevent, NULL); 553181430SstasMODULE_VERSION(cpuctl, CPUCTL_VERSION); 554