|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Merge
# HG changeset patch
# User Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
# Date 1322760408 0
# Node ID 3b409f65abae294b8ba9b6b34c5324854d780514
# Parent b6962c4b0dfd29b3fd1d02e6e0074ae871d99ec5
# Parent f30a33c5b5bd1e2b0bdffa3a649490157e451a4e
Merge
---
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/Makefile Thu Dec 01 17:26:48 2011 +0000
@@ -30,9 +30,10 @@
obj-y += msi.o
obj-y += ioport_emulate.o
obj-y += irq.o
-obj-y += microcode.o
obj-y += microcode_amd.o
obj-y += microcode_intel.o
+# This must come after the vendor specific files.
+obj-y += microcode.o
obj-y += mm.o
obj-y += mpparse.o
obj-y += nmi.o
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/efi/boot.c
--- a/xen/arch/x86/efi/boot.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/efi/boot.c Thu Dec 01 17:26:48 2011 +0000
@@ -49,6 +49,7 @@
static struct file __initdata cfg;
static struct file __initdata kernel;
static struct file __initdata ramdisk;
+static struct file __initdata ucode;
static struct file __initdata xsm;
static multiboot_info_t __initdata mbi = {
@@ -174,6 +175,8 @@
efi_bs->FreePages(kernel.addr, PFN_UP(kernel.size));
if ( ramdisk.addr )
efi_bs->FreePages(ramdisk.addr, PFN_UP(ramdisk.size));
+ if ( ucode.addr )
+ efi_bs->FreePages(ucode.addr, PFN_UP(ucode.size));
if ( xsm.addr )
efi_bs->FreePages(xsm.addr, PFN_UP(xsm.size));
@@ -806,6 +809,17 @@
efi_bs->FreePool(name.w);
}
+ name.s = get_value(&cfg, section.s, "ucode");
+ if ( !name.s )
+ name.s = get_value(&cfg, "global", "ucode");
+ if ( name.s )
+ {
+ microcode_set_module(mbi.mods_count);
+ split_value(name.s);
+ read_file(dir_handle, s2w(&name), &ucode);
+ efi_bs->FreePool(name.w);
+ }
+
name.s = get_value(&cfg, section.s, "xsm");
if ( name.s )
{
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/hvm/hvm.c Thu Dec 01 17:26:48 2011 +0000
@@ -1823,12 +1823,16 @@
return 0;
}
-/* We leave this function holding a lock on the p2m entry */
+/* On non-NULL return, we leave this function holding an additional
+ * ref on the underlying mfn, if any */
static void *__hvm_map_guest_frame(unsigned long gfn, bool_t writable)
{
+ void *map;
unsigned long mfn;
p2m_type_t p2mt;
+ struct page_info *pg;
struct domain *d = current->domain;
+ int rc;
mfn = mfn_x(writable
? get_gfn_unshare(d, gfn, &p2mt)
@@ -1850,7 +1854,21 @@
if ( writable )
paging_mark_dirty(d, mfn);
- return map_domain_page(mfn);
+ /* Get a ref on the page, considering that it could be shared */
+ pg = mfn_to_page(mfn);
+ rc = get_page(pg, d);
+ if ( !rc && !writable )
+ /* Page could be shared */
+ rc = get_page(pg, dom_cow);
+ if ( !rc )
+ {
+ put_gfn(d, gfn);
+ return NULL;
+ }
+
+ map = map_domain_page(mfn);
+ put_gfn(d, gfn);
+ return map;
}
void *hvm_map_guest_frame_rw(unsigned long gfn)
@@ -1866,11 +1884,16 @@
void hvm_unmap_guest_frame(void *p)
{
if ( p )
+ {
+ unsigned long mfn = domain_page_map_to_mfn(p);
unmap_domain_page(p);
+ put_page(mfn_to_page(mfn));
+ }
}
-static void *hvm_map_entry(unsigned long va, unsigned long *gfn)
+static void *hvm_map_entry(unsigned long va)
{
+ unsigned long gfn;
uint32_t pfec;
char *v;
@@ -1887,11 +1910,11 @@
* treat it as a kernel-mode read (i.e. no access checks).
*/
pfec = PFEC_page_present;
- *gfn = paging_gva_to_gfn(current, va, &pfec);
+ gfn = paging_gva_to_gfn(current, va, &pfec);
if ( (pfec == PFEC_page_paged) || (pfec == PFEC_page_shared) )
goto fail;
- v = hvm_map_guest_frame_rw(*gfn);
+ v = hvm_map_guest_frame_rw(gfn);
if ( v == NULL )
goto fail;
@@ -1902,11 +1925,9 @@
return NULL;
}
-static void hvm_unmap_entry(void *p, unsigned long gfn)
+static void hvm_unmap_entry(void *p)
{
hvm_unmap_guest_frame(p);
- if ( p && (gfn != INVALID_GFN) )
- put_gfn(current->domain, gfn);
}
static int hvm_load_segment_selector(
@@ -1918,7 +1939,6 @@
int fault_type = TRAP_invalid_tss;
struct cpu_user_regs *regs = guest_cpu_user_regs();
struct vcpu *v = current;
- unsigned long pdesc_gfn = INVALID_GFN;
if ( regs->eflags & X86_EFLAGS_VM )
{
@@ -1952,7 +1972,7 @@
if ( ((sel & 0xfff8) + 7) > desctab.limit )
goto fail;
- pdesc = hvm_map_entry(desctab.base + (sel & 0xfff8), &pdesc_gfn);
+ pdesc = hvm_map_entry(desctab.base + (sel & 0xfff8));
if ( pdesc == NULL )
goto hvm_map_fail;
@@ -2012,7 +2032,7 @@
desc.b |= 0x100;
skip_accessed_flag:
- hvm_unmap_entry(pdesc, pdesc_gfn);
+ hvm_unmap_entry(pdesc);
segr.base = (((desc.b << 0) & 0xff000000u) |
((desc.b << 16) & 0x00ff0000u) |
@@ -2028,7 +2048,7 @@
return 0;
unmap_and_fail:
- hvm_unmap_entry(pdesc, pdesc_gfn);
+ hvm_unmap_entry(pdesc);
fail:
hvm_inject_exception(fault_type, sel & 0xfffc, 0);
hvm_map_fail:
@@ -2043,7 +2063,7 @@
struct cpu_user_regs *regs = guest_cpu_user_regs();
struct segment_register gdt, tr, prev_tr, segr;
struct desc_struct *optss_desc = NULL, *nptss_desc = NULL, tss_desc;
- unsigned long eflags, optss_gfn = INVALID_GFN, nptss_gfn = INVALID_GFN;
+ unsigned long eflags;
int exn_raised, rc;
struct {
u16 back_link,__blh;
@@ -2069,11 +2089,11 @@
goto out;
}
- optss_desc = hvm_map_entry(gdt.base + (prev_tr.sel & 0xfff8), &optss_gfn);
+ optss_desc = hvm_map_entry(gdt.base + (prev_tr.sel & 0xfff8));
if ( optss_desc == NULL )
goto out;
- nptss_desc = hvm_map_entry(gdt.base + (tss_sel & 0xfff8), &nptss_gfn);
+ nptss_desc = hvm_map_entry(gdt.base + (tss_sel & 0xfff8));
if ( nptss_desc == NULL )
goto out;
@@ -2238,8 +2258,8 @@
}
out:
- hvm_unmap_entry(optss_desc, optss_gfn);
- hvm_unmap_entry(nptss_desc, nptss_gfn);
+ hvm_unmap_entry(optss_desc);
+ hvm_unmap_entry(nptss_desc);
}
#define HVMCOPY_from_guest (0u<<0)
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/hvm/svm/nestedsvm.c
--- a/xen/arch/x86/hvm/svm/nestedsvm.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c Thu Dec 01 17:26:48 2011 +0000
@@ -81,10 +81,6 @@
if (nv->nv_vvmcx == NULL)
return 0;
nv->nv_vvmcxaddr = vmcbaddr;
- /* put_gfn here even though the map survives beyond this caller.
- * The map can likely survive beyond a hypervisor exit, thus we
- * need to put the gfn */
- put_gfn(current->domain, vmcbaddr >> PAGE_SHIFT);
}
return 1;
@@ -358,7 +354,6 @@
ioport_80 = test_bit(0x80, ns_viomap);
ioport_ed = test_bit(0xed, ns_viomap);
hvm_unmap_guest_frame(ns_viomap);
- put_gfn(current->domain, svm->ns_iomap_pa >> PAGE_SHIFT);
svm->ns_iomap = nestedhvm_vcpu_iomap_get(ioport_80, ioport_ed);
@@ -889,7 +884,6 @@
enabled = test_bit(port, io_bitmap);
hvm_unmap_guest_frame(io_bitmap);
- put_gfn(current->domain, gfn);
if (!enabled)
return NESTEDHVM_VMEXIT_HOST;
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/hvm/vmx/vvmx.c
--- a/xen/arch/x86/hvm/vmx/vvmx.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/hvm/vmx/vvmx.c Thu Dec 01 17:26:48 2011 +0000
@@ -560,10 +560,7 @@
if (nvmx->iobitmap[index])
hvm_unmap_guest_frame (nvmx->iobitmap[index]);
gpa = __get_vvmcs(vcpu_nestedhvm(v).nv_vvmcx, vmcs_reg);
- nvmx->iobitmap[index] = hvm_map_guest_frame_ro (gpa >> PAGE_SHIFT);
- /* See comment in nestedsvm_vmcb_map re putting this gfn and
- * liveness of the map it backs */
- put_gfn(current->domain, gpa >> PAGE_SHIFT);
+ nvmx->iobitmap[index] = hvm_map_guest_frame_ro(gpa >> PAGE_SHIFT);
}
static inline void map_io_bitmap_all(struct vcpu *v)
@@ -1138,12 +1135,9 @@
if ( nvcpu->nv_vvmcxaddr == VMCX_EADDR )
{
- nvcpu->nv_vvmcx = hvm_map_guest_frame_rw (gpa >> PAGE_SHIFT);
+ nvcpu->nv_vvmcx = hvm_map_guest_frame_rw(gpa >> PAGE_SHIFT);
nvcpu->nv_vvmcxaddr = gpa;
map_io_bitmap_all (v);
- /* See comment in nestedsvm_vmcb_map regarding putting this
- * gfn and liveness of the map that uses it */
- put_gfn(current->domain, gpa >> PAGE_SHIFT);
}
vmreturn(regs, VMSUCCEED);
@@ -1205,7 +1199,6 @@
if ( vvmcs )
__set_vvmcs(vvmcs, NVMX_LAUNCH_STATE, 0);
hvm_unmap_guest_frame(vvmcs);
- put_gfn(current->domain, gpa >> PAGE_SHIFT);
}
vmreturn(regs, VMSUCCEED);
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/microcode.c
--- a/xen/arch/x86/microcode.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/microcode.c Thu Dec 01 17:26:48 2011 +0000
@@ -22,20 +22,56 @@
*/
#include <xen/config.h>
+#include <xen/cpu.h>
#include <xen/lib.h>
#include <xen/kernel.h>
#include <xen/init.h>
+#include <xen/notifier.h>
#include <xen/sched.h>
#include <xen/smp.h>
+#include <xen/softirq.h>
#include <xen/spinlock.h>
+#include <xen/tasklet.h>
#include <xen/guest_access.h>
-#include <asm/current.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
+#include <asm/setup.h>
#include <asm/microcode.h>
+static module_t __initdata ucode_mod;
+static void *(*__initdata ucode_mod_map)(const module_t *);
+static unsigned int __initdata ucode_mod_idx;
+static bool_t __initdata ucode_mod_forced;
+static cpumask_t __initdata init_mask;
+
+void __init microcode_set_module(unsigned int idx)
+{
+ ucode_mod_idx = idx;
+ ucode_mod_forced = 1;
+}
+
+static void __init parse_ucode(char *s)
+{
+ if ( !ucode_mod_forced )
+ ucode_mod_idx = simple_strtoul(s, NULL, 0);
+}
+custom_param("ucode", parse_ucode);
+
+void __init microcode_grab_module(
+ unsigned long *module_map,
+ const multiboot_info_t *mbi,
+ void *(*map)(const module_t *))
+{
+ module_t *mod = (module_t *)__va(mbi->mods_addr);
+
+ if ( !ucode_mod_idx || ucode_mod_idx >= mbi->mods_count ||
+ !__test_and_clear_bit(ucode_mod_idx, module_map) )
+ return;
+ ucode_mod = mod[ucode_mod_idx];
+ ucode_mod_map = map;
+}
+
const struct microcode_ops *microcode_ops;
static DEFINE_SPINLOCK(microcode_mutex);
@@ -69,30 +105,50 @@
int err;
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
struct cpu_signature nsig;
+ unsigned int cpu2;
- if ( !uci->mc.mc_valid )
- return -EIO;
+ spin_lock(µcode_mutex);
- /*
- * Let's verify that the 'cached' ucode does belong
- * to this cpu (a bit of paranoia):
- */
- err = microcode_ops->collect_cpu_info(cpu, &nsig);
+ err = microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
if ( err )
{
- microcode_fini_cpu(cpu);
+ __microcode_fini_cpu(cpu);
+ spin_unlock(µcode_mutex);
return err;
}
- if ( microcode_ops->microcode_resume_match(cpu, &nsig) )
+ if ( uci->mc.mc_valid )
{
- return microcode_ops->apply_microcode(cpu);
+ err = microcode_ops->microcode_resume_match(cpu, uci->mc.mc_valid);
+ if ( err >= 0 )
+ {
+ if ( err )
+ err = microcode_ops->apply_microcode(cpu);
+ spin_unlock(µcode_mutex);
+ return err;
+ }
}
- else
+
+ nsig = uci->cpu_sig;
+ __microcode_fini_cpu(cpu);
+ uci->cpu_sig = nsig;
+
+ err = -EIO;
+ for_each_online_cpu ( cpu2 )
{
- microcode_fini_cpu(cpu);
- return -EIO;
+ uci = &per_cpu(ucode_cpu_info, cpu2);
+ if ( uci->mc.mc_valid &&
+ microcode_ops->microcode_resume_match(cpu, uci->mc.mc_valid) > 0 )
+ {
+ err = microcode_ops->apply_microcode(cpu);
+ break;
+ }
}
+
+ __microcode_fini_cpu(cpu);
+ spin_unlock(µcode_mutex);
+
+ return err;
}
static int microcode_update_cpu(const void *buf, size_t size)
@@ -162,3 +218,78 @@
return continue_hypercall_on_cpu(info->cpu, do_microcode_update, info);
}
+
+static void __init _do_microcode_update(unsigned long data)
+{
+ microcode_update_cpu((void *)data, ucode_mod.mod_end);
+ cpumask_set_cpu(smp_processor_id(), &init_mask);
+}
+
+static int __init microcode_init(void)
+{
+ void *data;
+ static struct tasklet __initdata tasklet;
+ unsigned int cpu;
+
+ if ( !microcode_ops || !ucode_mod.mod_end )
+ return 0;
+
+ data = ucode_mod_map(&ucode_mod);
+ if ( !data )
+ return -ENOMEM;
+
+ softirq_tasklet_init(&tasklet, _do_microcode_update, (unsigned long)data);
+
+ for_each_online_cpu ( cpu )
+ {
+ tasklet_schedule_on_cpu(&tasklet, cpu);
+ do {
+ process_pending_softirqs();
+ } while ( !cpumask_test_cpu(cpu, &init_mask) );
+ }
+
+ ucode_mod_map(NULL);
+
+ return 0;
+}
+__initcall(microcode_init);
+
+static int microcode_percpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+
+ switch ( action )
+ {
+ case CPU_DEAD:
+ microcode_fini_cpu(cpu);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block microcode_percpu_nfb = {
+ .notifier_call = microcode_percpu_callback,
+};
+
+static int __init microcode_presmp_init(void)
+{
+ if ( microcode_ops )
+ {
+ if ( ucode_mod.mod_end )
+ {
+ void *data = ucode_mod_map(&ucode_mod);
+
+ if ( data )
+ microcode_update_cpu(data, ucode_mod.mod_end);
+
+ ucode_mod_map(NULL);
+ }
+
+ register_cpu_notifier(µcode_percpu_nfb);
+ }
+
+ return 0;
+}
+presmp_initcall(microcode_presmp_init);
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/microcode_amd.c
--- a/xen/arch/x86/microcode_amd.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/microcode_amd.c Thu Dec 01 17:26:48 2011 +0000
@@ -23,27 +23,53 @@
#include <xen/spinlock.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/microcode.h>
#define pr_debug(x...) ((void)0)
+struct equiv_cpu_entry {
+ uint32_t installed_cpu;
+ uint32_t fixed_errata_mask;
+ uint32_t fixed_errata_compare;
+ uint16_t equiv_cpu;
+ uint16_t reserved;
+} __attribute__((packed));
+
+struct microcode_header_amd {
+ uint32_t data_code;
+ uint32_t patch_id;
+ uint8_t mc_patch_data_id[2];
+ uint8_t mc_patch_data_len;
+ uint8_t init_flag;
+ uint32_t mc_patch_data_checksum;
+ uint32_t nb_dev_id;
+ uint32_t sb_dev_id;
+ uint16_t processor_rev_id;
+ uint8_t nb_rev_id;
+ uint8_t sb_rev_id;
+ uint8_t bios_api_rev;
+ uint8_t reserved1[3];
+ uint32_t match_reg[8];
+} __attribute__((packed));
+
#define UCODE_MAGIC 0x00414d44
#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
#define UCODE_UCODE_TYPE 0x00000001
#define UCODE_MAX_SIZE (2048)
-#define DEFAULT_UCODE_DATASIZE (896)
#define MC_HEADER_SIZE (sizeof(struct microcode_header_amd))
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
-#define DWSIZE (sizeof(uint32_t))
+
+struct microcode_amd {
+ struct microcode_header_amd hdr;
+ unsigned int mpb[(UCODE_MAX_SIZE - MC_HEADER_SIZE) / 4];
+ unsigned int equiv_cpu_table_size;
+ struct equiv_cpu_entry equiv_cpu_table[];
+};
/* serialize access to the physical write */
static DEFINE_SPINLOCK(microcode_update_lock);
-struct equiv_cpu_entry *equiv_cpu_table;
-
static int collect_cpu_info(int cpu, struct cpu_signature *csig)
{
struct cpuinfo_x86 *c = &cpu_data[cpu];
@@ -65,10 +91,11 @@
return 0;
}
-static int microcode_fits(void *mc, int cpu)
+static int microcode_fits(const struct microcode_amd *mc_amd, int cpu)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- struct microcode_header_amd *mc_header = mc;
+ const struct microcode_header_amd *mc_header = &mc_amd->hdr;
+ const struct equiv_cpu_entry *equiv_cpu_table = mc_amd->equiv_cpu_table;
unsigned int current_cpu_id;
unsigned int equiv_cpu_id = 0x0;
unsigned int i;
@@ -99,7 +126,7 @@
}
if ( mc_header->patch_id <= uci->cpu_sig.rev )
- return -EINVAL;
+ return 0;
printk(KERN_DEBUG "microcode: CPU%d found a matching microcode "
"update with version 0x%x (current=0x%x)\n",
@@ -186,17 +213,15 @@
return 0;
}
-static int install_equiv_cpu_table(const void *buf, uint32_t size,
- unsigned long *offset)
+static int install_equiv_cpu_table(
+ struct microcode_amd *mc_amd,
+ const uint32_t *buf_pos,
+ unsigned long *offset)
{
- const uint32_t *buf_pos = buf;
- unsigned long off;
-
- off = *offset;
- *offset = 0;
+ uint32_t size = buf_pos[2];
/* No more data */
- if ( off >= size )
+ if ( size + 12 >= *offset )
return -EINVAL;
if ( buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE )
@@ -213,15 +238,8 @@
return -EINVAL;
}
- equiv_cpu_table = xmalloc_bytes(size);
- if ( equiv_cpu_table == NULL )
- {
- printk(KERN_ERR "microcode: error, can't allocate "
- "memory for equiv CPU table\n");
- return -ENOMEM;
- }
-
- memcpy(equiv_cpu_table, (const void *)&buf_pos[3], size);
+ memcpy(mc_amd->equiv_cpu_table, &buf_pos[3], size);
+ mc_amd->equiv_cpu_table_size = size;
*offset = size + 12; /* add header length */
@@ -231,11 +249,11 @@
static int cpu_request_microcode(int cpu, const void *buf, size_t size)
{
const uint32_t *buf_pos;
- unsigned long offset = 0;
+ struct microcode_amd *mc_amd, *mc_old;
+ unsigned long offset = size;
int error = 0;
int ret;
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- void *mc;
/* We should bind the task to the CPU */
BUG_ON(cpu != raw_smp_processor_id());
@@ -249,59 +267,85 @@
return -EINVAL;
}
- error = install_equiv_cpu_table(buf, (uint32_t)(buf_pos[2]), &offset);
+ mc_amd = xmalloc_bytes(sizeof(*mc_amd) + buf_pos[2]);
+ if ( !mc_amd )
+ {
+ printk(KERN_ERR "microcode: error! "
+ "Can not allocate memory for microcode patch\n");
+ return -ENOMEM;
+ }
+
+ error = install_equiv_cpu_table(mc_amd, buf, &offset);
if ( error )
{
+ xfree(mc_amd);
printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
return -EINVAL;
}
- mc = xmalloc_bytes(UCODE_MAX_SIZE);
- if ( mc == NULL )
- {
- printk(KERN_ERR "microcode: error! "
- "Can not allocate memory for microcode patch\n");
- error = -ENOMEM;
- goto out;
- }
-
+ mc_old = uci->mc.mc_amd;
/* implicitely validates uci->mc.mc_valid */
- uci->mc.mc_amd = mc;
+ uci->mc.mc_amd = mc_amd;
/*
* It's possible the data file has multiple matching ucode,
* lets keep searching till the latest version
*/
- while ( (ret = get_next_ucode_from_buffer_amd(mc, buf, size, &offset)) ==
0)
+ while ( (ret = get_next_ucode_from_buffer_amd(&mc_amd->hdr, buf, size,
+ &offset)) == 0 )
{
- error = microcode_fits(mc, cpu);
+ error = microcode_fits(mc_amd, cpu);
if (error <= 0)
continue;
error = apply_microcode(cpu);
if (error == 0)
+ {
+ error = 1;
break;
+ }
}
+ if ( ret < 0 )
+ error = ret;
+
/* On success keep the microcode patch for
* re-apply on resume.
*/
- if (error) {
- xfree(mc);
- mc = NULL;
+ if (error == 1)
+ {
+ xfree(mc_old);
+ return 0;
}
- uci->mc.mc_amd = mc;
-
-out:
- xfree(equiv_cpu_table);
- equiv_cpu_table = NULL;
+ xfree(mc_amd);
+ uci->mc.mc_amd = mc_old;
return error;
}
-static int microcode_resume_match(int cpu, struct cpu_signature *nsig)
+static int microcode_resume_match(int cpu, const void *mc)
{
- return 0;
+ struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
+ struct microcode_amd *mc_amd = uci->mc.mc_amd;
+ const struct microcode_amd *src = mc;
+ int res = microcode_fits(src, cpu);
+
+ if ( res <= 0 )
+ return res;
+
+ if ( src != mc_amd )
+ {
+ xfree(mc_amd);
+ mc_amd = xmalloc_bytes(sizeof(*src) + src->equiv_cpu_table_size);
+ uci->mc.mc_amd = mc_amd;
+ if ( !mc_amd )
+ return -ENOMEM;
+ memcpy(mc_amd, src, UCODE_MAX_SIZE);
+ memcpy(mc_amd->equiv_cpu_table, src->equiv_cpu_table,
+ src->equiv_cpu_table_size);
+ }
+
+ return 1;
}
static const struct microcode_ops microcode_amd_ops = {
@@ -317,4 +361,4 @@
microcode_ops = µcode_amd_ops;
return 0;
}
-__initcall(microcode_init_amd);
+presmp_initcall(microcode_init_amd);
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/microcode_intel.c
--- a/xen/arch/x86/microcode_intel.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/microcode_intel.c Thu Dec 01 17:26:48 2011 +0000
@@ -30,12 +30,43 @@
#include <xen/spinlock.h>
#include <asm/msr.h>
-#include <asm/uaccess.h>
#include <asm/processor.h>
#include <asm/microcode.h>
#define pr_debug(x...) ((void)0)
+struct microcode_header_intel {
+ unsigned int hdrver;
+ unsigned int rev;
+ unsigned int date;
+ unsigned int sig;
+ unsigned int cksum;
+ unsigned int ldrver;
+ unsigned int pf;
+ unsigned int datasize;
+ unsigned int totalsize;
+ unsigned int reserved[3];
+};
+
+struct microcode_intel {
+ struct microcode_header_intel hdr;
+ unsigned int bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+ unsigned int sig;
+ unsigned int pf;
+ unsigned int cksum;
+};
+
+struct extended_sigtable {
+ unsigned int count;
+ unsigned int cksum;
+ unsigned int reserved[3];
+ struct extended_signature sigs[0];
+};
+
#define DEFAULT_UCODE_DATASIZE (2000)
#define MC_HEADER_SIZE (sizeof(struct microcode_header_intel))
#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
@@ -98,7 +129,8 @@
}
static inline int microcode_update_match(
- int cpu_num, struct microcode_header_intel *mc_header, int sig, int pf)
+ int cpu_num, const struct microcode_header_intel *mc_header,
+ int sig, int pf)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu_num);
@@ -200,11 +232,11 @@
* return 1 - found update
* return < 0 - error
*/
-static int get_matching_microcode(void *mc, int cpu)
+static int get_matching_microcode(const void *mc, int cpu)
{
struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
- struct microcode_header_intel *mc_header = mc;
- struct extended_sigtable *ext_header;
+ const struct microcode_header_intel *mc_header = mc;
+ const struct extended_sigtable *ext_header;
unsigned long total_size = get_totalsize(mc_header);
int ext_sigcount, i;
struct extended_signature *ext_sig;
@@ -229,6 +261,8 @@
}
return 0;
find:
+ if ( uci->mc.mc_intel && uci->mc.mc_intel->hdr.rev >= mc_header->rev )
+ return 0;
pr_debug("microcode: CPU%d found a matching microcode update with"
" version 0x%x (current=0x%x)\n",
cpu, mc_header->rev, uci->cpu_sig.rev);
@@ -239,10 +273,8 @@
return -ENOMEM;
}
- /* free previous update file */
+ memcpy(new_mc, mc, total_size);
xfree(uci->mc.mc_intel);
-
- memcpy(new_mc, mc, total_size);
uci->mc.mc_intel = new_mc;
return 1;
}
@@ -361,12 +393,9 @@
return error;
}
-static int microcode_resume_match(int cpu, struct cpu_signature *nsig)
+static int microcode_resume_match(int cpu, const void *mc)
{
- struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
-
- return (sigmatch(nsig->sig, uci->cpu_sig.sig, nsig->pf, uci->cpu_sig.pf) &&
- (uci->cpu_sig.rev > nsig->rev));
+ return get_matching_microcode(mc, cpu);
}
static const struct microcode_ops microcode_intel_ops = {
@@ -382,4 +411,4 @@
microcode_ops = µcode_intel_ops;
return 0;
}
-__initcall(microcode_init_intel);
+presmp_initcall(microcode_init_intel);
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/mm.c Thu Dec 01 17:26:48 2011 +0000
@@ -3572,7 +3572,8 @@
rc = -ENOENT;
break;
}
- else if ( p2m_ram_paging_in_start == l1e_p2mt &&
!mfn_valid(mfn) )
+ else if ( p2m_ram_paging_in_start == l1e_p2mt &&
+ !mfn_valid(l1emfn) )
{
put_gfn(pg_owner, l1egfn);
rc = -ENOENT;
@@ -3620,7 +3621,8 @@
rc = -ENOENT;
break;
}
- else if ( p2m_ram_paging_in_start == l2e_p2mt &&
!mfn_valid(mfn) )
+ else if ( p2m_ram_paging_in_start == l2e_p2mt &&
+ !mfn_valid(l2emfn) )
{
put_gfn(pg_owner, l2egfn);
rc = -ENOENT;
@@ -3654,7 +3656,8 @@
rc = -ENOENT;
break;
}
- else if ( p2m_ram_paging_in_start == l3e_p2mt &&
!mfn_valid(mfn) )
+ else if ( p2m_ram_paging_in_start == l3e_p2mt &&
+ !mfn_valid(l3emfn) )
{
put_gfn(pg_owner, l3egfn);
rc = -ENOENT;
@@ -3688,7 +3691,8 @@
rc = -ENOENT;
break;
}
- else if ( p2m_ram_paging_in_start == l4e_p2mt &&
!mfn_valid(mfn) )
+ else if ( p2m_ram_paging_in_start == l4e_p2mt &&
+ !mfn_valid(l4emfn) )
{
put_gfn(pg_owner, l4egfn);
rc = -ENOENT;
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/setup.c
--- a/xen/arch/x86/setup.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/setup.c Thu Dec 01 17:26:48 2011 +0000
@@ -550,10 +550,10 @@
{
char *memmap_type = NULL;
char *cmdline, *kextra, *loader;
- unsigned int initrdidx = 1;
+ unsigned int initrdidx;
multiboot_info_t *mbi = __va(mbi_p);
module_t *mod = (module_t *)__va(mbi->mods_addr);
- unsigned long nr_pages, modules_headroom;
+ unsigned long nr_pages, modules_headroom, *module_map;
int i, j, e820_warn = 0, bytes = 0;
bool_t acpi_boot_table_init_done = 0;
struct ns16550_defaults ns16550 = {
@@ -1229,7 +1229,13 @@
init_IRQ();
- xsm_init(&initrdidx, mbi, bootstrap_map);
+ module_map = xmalloc_array(unsigned long, BITS_TO_LONGS(mbi->mods_count));
+ bitmap_fill(module_map, mbi->mods_count);
+ __clear_bit(0, module_map); /* Dom0 kernel is always first */
+
+ xsm_init(module_map, mbi, bootstrap_map);
+
+ microcode_grab_module(module_map, mbi, bootstrap_map);
timer_init();
@@ -1356,6 +1362,12 @@
if ( xen_cpuidle )
xen_processor_pmbits |= XEN_PROCESSOR_PM_CX;
+ initrdidx = find_first_bit(module_map, mbi->mods_count);
+ if ( bitmap_weight(module_map, mbi->mods_count) > 1 )
+ printk(XENLOG_WARNING
+ "Multiple initrd candidates, picking module #%u\n",
+ initrdidx);
+
/*
* We're going to setup domain0 using the module(s) that we stashed safely
* above our heap. The second module, if present, is an initrd ramdisk.
diff -r b6962c4b0dfd -r 3b409f65abae xen/arch/x86/x86_32/domain_page.c
--- a/xen/arch/x86/x86_32/domain_page.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/arch/x86/x86_32/domain_page.c Thu Dec 01 17:26:48 2011 +0000
@@ -265,3 +265,15 @@
idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT;
set_bit(idx, garbage);
}
+
+/* Translate a map-domain-page'd address to the underlying MFN */
+unsigned long domain_page_map_to_mfn(void *va)
+{
+ l1_pgentry_t *l1e;
+
+ ASSERT( (((unsigned long) va) >= MAPCACHE_VIRT_START) &&
+ (((unsigned long) va) <= MAPCACHE_VIRT_END) );
+ l1e = &__linear_l1_table[
+ l1_linear_offset((unsigned long) va)];
+ return l1e_get_pfn(*l1e);
+}
diff -r b6962c4b0dfd -r 3b409f65abae xen/include/asm-x86/microcode.h
--- a/xen/include/asm-x86/microcode.h Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/include/asm-x86/microcode.h Thu Dec 01 17:26:48 2011 +0000
@@ -7,74 +7,12 @@
struct ucode_cpu_info;
struct microcode_ops {
- int (*microcode_resume_match)(int cpu, struct cpu_signature *nsig);
+ int (*microcode_resume_match)(int cpu, const void *mc);
int (*cpu_request_microcode)(int cpu, const void *buf, size_t size);
int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
int (*apply_microcode)(int cpu);
};
-struct microcode_header_intel {
- unsigned int hdrver;
- unsigned int rev;
- unsigned int date;
- unsigned int sig;
- unsigned int cksum;
- unsigned int ldrver;
- unsigned int pf;
- unsigned int datasize;
- unsigned int totalsize;
- unsigned int reserved[3];
-};
-
-struct microcode_intel {
- struct microcode_header_intel hdr;
- unsigned int bits[0];
-};
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
- unsigned int sig;
- unsigned int pf;
- unsigned int cksum;
-};
-
-struct extended_sigtable {
- unsigned int count;
- unsigned int cksum;
- unsigned int reserved[3];
- struct extended_signature sigs[0];
-};
-
-struct equiv_cpu_entry {
- uint32_t installed_cpu;
- uint32_t fixed_errata_mask;
- uint32_t fixed_errata_compare;
- uint16_t equiv_cpu;
- uint16_t reserved;
-} __attribute__((packed));
-
-struct microcode_header_amd {
- uint32_t data_code;
- uint32_t patch_id;
- uint8_t mc_patch_data_id[2];
- uint8_t mc_patch_data_len;
- uint8_t init_flag;
- uint32_t mc_patch_data_checksum;
- uint32_t nb_dev_id;
- uint32_t sb_dev_id;
- uint16_t processor_rev_id;
- uint8_t nb_rev_id;
- uint8_t sb_rev_id;
- uint8_t bios_api_rev;
- uint8_t reserved1[3];
- uint32_t match_reg[8];
-} __attribute__((packed));
-
-struct microcode_amd {
- struct microcode_header_amd hdr;
- unsigned int mpb[0];
-};
-
struct cpu_signature {
unsigned int sig;
unsigned int pf;
diff -r b6962c4b0dfd -r 3b409f65abae xen/include/asm-x86/processor.h
--- a/xen/include/asm-x86/processor.h Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/include/asm-x86/processor.h Thu Dec 01 17:26:48 2011 +0000
@@ -599,6 +599,7 @@
int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val);
int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val);
+void microcode_set_module(unsigned int);
int microcode_update(XEN_GUEST_HANDLE(const_void), unsigned long len);
int microcode_resume_cpu(int cpu);
diff -r b6962c4b0dfd -r 3b409f65abae xen/include/asm-x86/setup.h
--- a/xen/include/asm-x86/setup.h Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/include/asm-x86/setup.h Thu Dec 01 17:26:48 2011 +0000
@@ -44,4 +44,7 @@
int xen_in_range(unsigned long mfn);
void arch_get_xen_caps(xen_capabilities_info_t *info);
+void microcode_grab_module(
+ unsigned long *, const multiboot_info_t *, void *(*)(const module_t *));
+
#endif
diff -r b6962c4b0dfd -r 3b409f65abae xen/include/xen/domain_page.h
--- a/xen/include/xen/domain_page.h Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/include/xen/domain_page.h Thu Dec 01 17:26:48 2011 +0000
@@ -26,6 +26,12 @@
*/
void unmap_domain_page(const void *va);
+
+/*
+ * Given a VA from map_domain_page(), return its underlying MFN.
+ */
+unsigned long domain_page_map_to_mfn(void *va);
+
/*
* Similar to the above calls, except the mapping is accessible in all
* address spaces (not just within the VCPU that created the mapping). Global
@@ -102,6 +108,7 @@
#define map_domain_page(mfn) mfn_to_virt(mfn)
#define __map_domain_page(pg) page_to_virt(pg)
#define unmap_domain_page(va) ((void)(va))
+#define domain_page_map_to_mfn(va) virt_to_mfn((unsigned long)(va))
#define map_domain_page_global(mfn) mfn_to_virt(mfn)
#define __map_domain_page_global(pg) page_to_virt(pg)
diff -r b6962c4b0dfd -r 3b409f65abae xen/include/xsm/xsm.h
--- a/xen/include/xsm/xsm.h Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/include/xsm/xsm.h Thu Dec 01 17:26:48 2011 +0000
@@ -454,14 +454,15 @@
}
#ifdef XSM_ENABLE
-extern int xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+extern int xsm_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *));
-extern int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t
*mbi,
+extern int xsm_policy_init(unsigned long *module_map,
+ const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *));
extern int register_xsm(struct xsm_operations *ops);
extern int unregister_xsm(struct xsm_operations *ops);
#else
-static inline int xsm_init (unsigned int *initrdidx,
+static inline int xsm_init (unsigned long *module_map,
const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
diff -r b6962c4b0dfd -r 3b409f65abae xen/xsm/xsm_core.c
--- a/xen/xsm/xsm_core.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/xsm/xsm_core.c Thu Dec 01 17:26:48 2011 +0000
@@ -43,7 +43,7 @@
}
}
-int __init xsm_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+int __init xsm_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
int ret = 0;
@@ -52,7 +52,7 @@
if ( XSM_MAGIC )
{
- ret = xsm_policy_init(initrdidx, mbi, bootstrap_map);
+ ret = xsm_policy_init(module_map, mbi, bootstrap_map);
if ( ret )
{
bootstrap_map(NULL);
diff -r b6962c4b0dfd -r 3b409f65abae xen/xsm/xsm_policy.c
--- a/xen/xsm/xsm_policy.c Thu Dec 01 17:25:39 2011 +0000
+++ b/xen/xsm/xsm_policy.c Thu Dec 01 17:26:48 2011 +0000
@@ -20,11 +20,12 @@
#include <xsm/xsm.h>
#include <xen/multiboot.h>
+#include <asm/bitops.h>
char *__initdata policy_buffer = NULL;
u32 __initdata policy_size = 0;
-int xsm_policy_init(unsigned int *initrdidx, const multiboot_info_t *mbi,
+int xsm_policy_init(unsigned long *module_map, const multiboot_info_t *mbi,
void *(*bootstrap_map)(const module_t *))
{
int i;
@@ -35,10 +36,13 @@
/*
* Try all modules and see whichever could be the binary policy.
- * Adjust the initrdidx if module[1] is the binary policy.
+ * Adjust module_map for the module that is the binary policy.
*/
for ( i = mbi->mods_count-1; i >= 1; i-- )
{
+ if ( !test_bit(i, module_map) )
+ continue;
+
_policy_start = bootstrap_map(mod + i);
_policy_len = mod[i].mod_end;
@@ -50,8 +54,7 @@
printk("Policy len 0x%lx, start at %p.\n",
_policy_len,_policy_start);
- if ( i == 1 )
- *initrdidx = (mbi->mods_count > 2) ? 2 : 0;
+ __clear_bit(i, module_map);
break;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |