diff options
Diffstat (limited to 'sys/dev/cpuctl/cpuctl.c')
-rw-r--r-- | sys/dev/cpuctl/cpuctl.c | 53 |
1 files changed, 23 insertions, 30 deletions
diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c index c3e656e..e0c0bf7 100644 --- a/sys/dev/cpuctl/cpuctl.c +++ b/sys/dev/cpuctl/cpuctl.c @@ -63,7 +63,7 @@ static d_ioctl_t cpuctl_ioctl; # define DPRINTF(...) #endif -#define UCODE_SIZE_MAX (32 * 1024) +#define UCODE_SIZE_MAX (4 * 1024 * 1024) static int cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, struct thread *td); @@ -377,13 +377,24 @@ fail: return (ret); } +/* + * NB: MSR 0xc0010020, MSR_K8_UCODE_UPDATE, is not documented by AMD. + * Coreboot, illumos and Linux source code was used to understand + * its workings. + */ +static void +amd_ucode_wrmsr(void *ucode_ptr) +{ + uint32_t tmp[4]; + + wrmsr_safe(MSR_K8_UCODE_UPDATE, (uintptr_t)ucode_ptr); + do_cpuid(0, tmp); +} + static int update_amd(int cpu, cpuctl_update_args_t *args, struct thread *td) { - void *ptr = NULL; - uint32_t tmp[4]; - int is_bound = 0; - int oldcpu; + void *ptr; int ret; if (args->size == 0 || args->data == NULL) { @@ -394,41 +405,23 @@ update_amd(int cpu, cpuctl_update_args_t *args, struct thread *td) DPRINTF("[cpuctl,%d]: firmware image too large", __LINE__); return (EINVAL); } + /* - * XXX Might not require contignous address space - needs check + * 16 byte alignment required. Rely on the fact that + * malloc(9) always returns the pointer aligned at least on + * the size of the allocation. */ - ptr = contigmalloc(args->size, M_CPUCTL, 0, 0, 0xffffffff, 16, 0); - if (ptr == NULL) { - DPRINTF("[cpuctl,%d]: cannot allocate %zd bytes of memory", - __LINE__, args->size); - return (ENOMEM); - } + ptr = malloc(args->size + 16, M_CPUCTL, M_ZERO | M_WAITOK); if (copyin(args->data, ptr, args->size) != 0) { DPRINTF("[cpuctl,%d]: copyin %p->%p of %zd bytes failed", __LINE__, args->data, ptr, args->size); ret = EFAULT; goto fail; } - oldcpu = td->td_oncpu; - is_bound = cpu_sched_is_bound(td); - set_cpu(cpu, td); - critical_enter(); - - /* - * Perform update. - */ - wrmsr_safe(MSR_K8_UCODE_UPDATE, (uintptr_t)ptr); - - /* - * Serialize instruction flow. - */ - do_cpuid(0, tmp); - critical_exit(); - restore_cpu(oldcpu, is_bound, td); + smp_rendezvous(NULL, amd_ucode_wrmsr, NULL, ptr); ret = 0; fail: - if (ptr != NULL) - contigfree(ptr, args->size, M_CPUCTL); + free(ptr, M_CPUCTL); return (ret); } |