ia64/xen-unstable

annotate xen/arch/x86/microcode.c @ 18506:f163138e3340

x86, microcode: Free microcode_info struct at end of hypercall.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Sep 16 13:49:16 2008 +0100 (2008-09-16)
parents 879330497672
children fb0dc8143932
rev   line source
kaf24@3362 1 /*
keir@18497 2 * Intel CPU Microcode Update Driver for Linux
keir@18489 3 *
keir@18497 4 * Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
keir@18497 5 * 2006 Shaohua Li <shaohua.li@intel.com> *
keir@18497 6 * This driver allows to upgrade microcode on Intel processors
keir@18497 7 * belonging to IA-32 family - PentiumPro, Pentium II,
keir@18497 8 * Pentium III, Xeon, Pentium 4, etc.
keir@18497 9 *
keir@18497 10 * Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
keir@18497 11 * Software Developer's Manual
keir@18497 12 * Order Number 253668 or free download from:
keir@18497 13 *
keir@18497 14 * http://developer.intel.com/design/pentium4/manuals/253668.htm
keir@18497 15 *
keir@18497 16 * For more information, go to http://www.urbanmyth.org/microcode
keir@18497 17 *
keir@18497 18 * This program is free software; you can redistribute it and/or
keir@18497 19 * modify it under the terms of the GNU General Public License
keir@18497 20 * as published by the Free Software Foundation; either version
keir@18497 21 * 2 of the License, or (at your option) any later version.
kaf24@3362 22 */
kaf24@3362 23
kaf24@3362 24 #include <xen/config.h>
cl349@5285 25 #include <xen/lib.h>
kaf24@3362 26 #include <xen/kernel.h>
kaf24@3362 27 #include <xen/init.h>
kaf24@3362 28 #include <xen/sched.h>
cl349@5287 29 #include <xen/smp.h>
kaf24@3362 30 #include <xen/spinlock.h>
keir@18489 31 #include <xen/guest_access.h>
kaf24@3362 32
cl349@5291 33 #include <asm/current.h>
kaf24@3362 34 #include <asm/msr.h>
kaf24@3362 35 #include <asm/uaccess.h>
kaf24@3362 36 #include <asm/processor.h>
keir@18489 37 #include <asm/microcode.h>
kaf24@3362 38
keir@18489 39 const struct microcode_ops *microcode_ops;
kaf24@3362 40
keir@18489 41 static DEFINE_SPINLOCK(microcode_mutex);
kaf24@3362 42
keir@18489 43 struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
keir@18489 44
keir@18505 45 struct microcode_info {
keir@18505 46 unsigned int cpu;
keir@18505 47 uint32_t buffer_size;
keir@18505 48 int error;
keir@18505 49 char buffer[1];
keir@18489 50 };
keir@18489 51
keir@18489 52 static void microcode_fini_cpu(int cpu)
kaf24@3362 53 {
keir@18497 54 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
kaf24@3362 55
keir@18497 56 spin_lock(&microcode_mutex);
keir@18499 57 xfree(uci->mc.valid_mc);
keir@18499 58 uci->mc.valid_mc = NULL;
keir@18497 59 uci->valid = 0;
keir@18497 60 spin_unlock(&microcode_mutex);
keir@18489 61 }
kaf24@3362 62
keir@18489 63 static int collect_cpu_info(int cpu)
keir@18489 64 {
keir@18497 65 int err = 0;
keir@18497 66 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18489 67
keir@18497 68 memset(uci, 0, sizeof(*uci));
keir@18497 69 err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
keir@18497 70 if ( !err )
keir@18497 71 uci->valid = 1;
keir@18489 72
keir@18497 73 return err;
keir@18489 74 }
keir@18489 75
keir@18489 76 static int microcode_resume_cpu(int cpu)
keir@18489 77 {
keir@18497 78 int err = 0;
keir@18497 79 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18497 80 struct cpu_signature nsig;
keir@18489 81
keir@18497 82 gdprintk(XENLOG_INFO, "microcode: CPU%d resumed\n", cpu);
kaf24@3362 83
keir@18497 84 if ( !uci->mc.valid_mc )
keir@18497 85 return -EIO;
keir@18489 86
keir@18497 87 /*
keir@18497 88 * Let's verify that the 'cached' ucode does belong
keir@18497 89 * to this cpu (a bit of paranoia):
keir@18497 90 */
keir@18497 91 err = microcode_ops->collect_cpu_info(cpu, &nsig);
keir@18497 92 if ( err )
keir@18497 93 {
keir@18497 94 microcode_fini_cpu(cpu);
keir@18497 95 return err;
keir@18497 96 }
keir@18489 97
keir@18497 98 if ( memcmp(&nsig, &uci->cpu_sig, sizeof(nsig)) )
keir@18497 99 {
keir@18497 100 microcode_fini_cpu(cpu);
keir@18497 101 /* Should we look for a new ucode here? */
keir@18497 102 return -EIO;
keir@18497 103 }
keir@18497 104
keir@18497 105 err = microcode_ops->apply_microcode(cpu);
keir@18497 106
keir@18497 107 return err;
kaf24@3362 108 }
kaf24@3362 109
keir@18505 110 static int microcode_update_cpu(const void *buf, size_t size)
kaf24@3362 111 {
keir@18505 112 int err;
keir@18505 113 unsigned int cpu = smp_processor_id();
keir@18497 114 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
keir@18489 115
keir@18497 116 spin_lock(&microcode_mutex);
keir@18489 117
keir@18497 118 /*
keir@18497 119 * Check if the system resume is in progress (uci->valid != NULL),
keir@18497 120 * otherwise just request a firmware:
keir@18497 121 */
keir@18497 122 if ( uci->valid )
keir@18497 123 {
keir@18497 124 err = microcode_resume_cpu(cpu);
keir@18497 125 }
keir@18497 126 else
keir@18497 127 {
keir@18497 128 err = collect_cpu_info(cpu);
keir@18497 129 if ( !err && uci->valid )
keir@18497 130 err = microcode_ops->cpu_request_microcode(cpu, buf, size);
keir@18497 131 }
keir@18497 132
keir@18497 133 spin_unlock(&microcode_mutex);
keir@18497 134
keir@18497 135 return err;
kaf24@3362 136 }
kaf24@3362 137
keir@18505 138 static long do_microcode_update(void *_info)
kaf24@3362 139 {
keir@18505 140 struct microcode_info *info = _info;
keir@18505 141 int error;
kaf24@3362 142
keir@18505 143 BUG_ON(info->cpu != smp_processor_id());
kaf24@3362 144
keir@18505 145 error = microcode_update_cpu(info->buffer, info->buffer_size);
keir@18505 146 if ( error )
keir@18505 147 info->error = error;
kaf24@3362 148
keir@18505 149 info->cpu = next_cpu(info->cpu, cpu_online_map);
keir@18506 150 if ( info->cpu < NR_CPUS )
keir@18506 151 return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
keir@18505 152
keir@18506 153 error = info->error;
keir@18506 154 xfree(info);
keir@18506 155 return error;
keir@18506 156
kaf24@3362 157 }
kaf24@3362 158
keir@18417 159 int microcode_update(XEN_GUEST_HANDLE(const_void) buf, unsigned long len)
kaf24@3362 160 {
keir@18497 161 int ret;
keir@18505 162 struct microcode_info *info;
keir@18489 163
keir@18505 164 if ( len != (uint32_t)len )
keir@18497 165 return -E2BIG;
kfraser@10545 166
keir@18499 167 if ( microcode_ops == NULL )
keir@18497 168 return -EINVAL;
kfraser@10545 169
keir@18505 170 info = xmalloc_bytes(sizeof(*info) + len);
keir@18505 171 if ( info == NULL )
keir@18497 172 return -ENOMEM;
keir@18497 173
keir@18505 174 ret = copy_from_guest(info->buffer, buf, len);
keir@18497 175 if ( ret != 0 )
keir@18505 176 {
keir@18505 177 xfree(info);
keir@18497 178 return ret;
keir@18505 179 }
keir@18497 180
keir@18505 181 info->buffer_size = len;
keir@18505 182 info->error = 0;
keir@18505 183 info->cpu = first_cpu(cpu_online_map);
keir@18497 184
keir@18505 185 return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
kaf24@3362 186 }