ia64/xen-unstable

view xen/arch/x86/microcode.c @ 19060:fb0dc8143932

x86: update microcode support

- Container header file holding the patches changed. Update to new
format.
- in cpu_request_microcode() move heap re-allocation & copy out of the
loop.
Side-effect: Remove limitation in only supporting fixed sized
microcode patches. Also simplifies code a lot.
- cleanup: use rdmsr and wrmsrl instead of inlined assembler
- pass ucode_cpu_info as arguments. Improves reentrancy.
- cleanup: simplify struct ucode_cpu_info and remove
get_matching_microcode hook. Side-effect: reduces kernel size.
- bugfix: fix xen kernel memory leak in error path. equiv_cpu_table
was not freed.

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