# HG changeset patch # User Boris Ostrovsky <boris.ostrovsky@amd.com> # Date 1324656297 18000 # Node ID a063cab704c21c7adc2d69c47b50433294f9cd02 # Parent 548923a4fcf66b51d6d5332f5de575116e2ce67a Xen 3.4: x86/ucode: fix for AMD Fam15 CPUs Remove hardcoded maximum size a microcode patch can have. This is dynamic now. The microcode patch for family15h can be larger than 2048 bytes and gets silently truncated. Signed-off-by: Boris Ostrovsky <boris.ostrovsky@amd.com> Acked-by: Christoph Egger <Christoph.Egger@amd.com> xen-unstable changeset: 24412:ca5f588bd203 xen-unstable date: Thu Dec 15 11:00:09 2011 +0100 diff -r 548923a4fcf6 -r a063cab704c2 xen/arch/x86/microcode_amd.c --- a/xen/arch/x86/microcode_amd.c Tue Dec 20 20:50:49 2011 -0500 +++ b/xen/arch/x86/microcode_amd.c Fri Dec 23 11:04:57 2011 -0500 @@ -33,11 +33,11 @@ #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 mpbhdr { + uint32_t type; + uint32_t len; + uint8_t data[]; +}; /* serialize access to the physical write */ static DEFINE_SPINLOCK(microcode_update_lock); @@ -66,10 +66,10 @@ static int collect_cpu_info(int cpu, str 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 = ucode_cpu_info + cpu; - struct microcode_header_amd *mc_header = mc; + struct microcode_header_amd *mc_header = mc_amd->mpb; unsigned int current_cpu_id; unsigned int equiv_cpu_id = 0x0; unsigned int i; @@ -98,9 +98,9 @@ static int microcode_fits(void *mc, int if ( !equiv_cpu_id ) { - printk(KERN_ERR "microcode: CPU%d cpu_id " + printk(KERN_INFO "microcode: CPU%d cpu_id " "not found in equivalent cpu table\n", cpu); - return -EINVAL; + return 0; } if ( (mc_header->processor_rev_id) != equiv_cpu_id ) @@ -112,14 +112,14 @@ static int microcode_fits(void *mc, int } if ( mc_header->patch_id <= uci->cpu_sig.rev ) - return -EINVAL; + return 0; printk(KERN_INFO "microcode: CPU%d found a matching microcode " "update with version 0x%x (current=0x%x)\n", cpu, mc_header->patch_id, uci->cpu_sig.rev); out: - return 0; + return 1; } static int apply_microcode(int cpu) @@ -128,16 +128,21 @@ static int apply_microcode(int cpu) struct ucode_cpu_info *uci = ucode_cpu_info + cpu; uint32_t rev, dummy; struct microcode_amd *mc_amd = uci->mc.mc_amd; + struct microcode_header_amd *hdr; /* We should bind the task to the CPU */ BUG_ON(raw_smp_processor_id() != cpu); if ( mc_amd == NULL ) - return -EINVAL; + return -EINVAL; + + hdr = mc_amd->mpb; + if ( hdr == NULL ) + return -EINVAL; spin_lock_irqsave(µcode_update_lock, flags); - wrmsrl(MSR_AMD_PATCHLOADER, (unsigned long)&mc_amd->hdr.data_code); + wrmsrl(MSR_AMD_PATCHLOADER, (unsigned long)hdr); /* get patch id after patching */ rdmsr(MSR_AMD_PATCHLEVEL, rev, dummy); @@ -145,61 +150,67 @@ static int apply_microcode(int cpu) spin_unlock_irqrestore(µcode_update_lock, flags); /* check current patch id and patch''s id for match */ - if ( rev != mc_amd->hdr.patch_id ) + if ( rev != hdr->patch_id ) { printk(KERN_ERR "microcode: CPU%d update from revision " "0x%x to 0x%x failed\n", cpu, - mc_amd->hdr.patch_id, rev); + hdr->patch_id, rev); return -EIO; } printk("microcode: CPU%d updated from revision " "0x%x to 0x%x \n", - cpu, uci->cpu_sig.rev, mc_amd->hdr.patch_id); + cpu, uci->cpu_sig.rev, hdr->patch_id); uci->cpu_sig.rev = rev; return 0; } -static int get_next_ucode_from_buffer_amd(void *mc, const void *buf, - size_t size, unsigned long *offset) +static int get_next_ucode_from_buffer_amd(struct microcode_amd *mc_amd, + const void *buf, size_t bufsize, + unsigned long *offset) { - struct microcode_header_amd *mc_header; - size_t total_size; const uint8_t *bufp = buf; unsigned long off; + const struct mpbhdr *mpbuf; off = *offset; /* No more data */ - if ( off >= size ) + if ( off >= bufsize ) return 1; - if ( bufp[off] != UCODE_UCODE_TYPE ) + mpbuf = (const struct mpbhdr *)&bufp[off]; + if ( mpbuf->type != UCODE_UCODE_TYPE ) { printk(KERN_ERR "microcode: error! " "Wrong microcode payload type field\n"); return -EINVAL; } - mc_header = (struct microcode_header_amd *)(&bufp[off+8]); + printk(KERN_INFO "microcode: size %lu, total_size %u, offset %ld\n", + bufsize, mpbuf->len, off); - total_size = (unsigned long) (bufp[off+4] + (bufp[off+5] << 8)); - - printk(KERN_INFO "microcode: size %lu, total_size %lu, offset %ld\n", - (unsigned long)size, total_size, off); - - if ( (off + total_size) > size ) + if ( (off + mpbuf->len) > bufsize ) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); return -EINVAL; } - memset(mc, 0, UCODE_MAX_SIZE); - memcpy(mc, (const void *)(&bufp[off + 8]), total_size); + if (mc_amd->mpb_size < mpbuf->len) { + if (mc_amd->mpb) { + xfree(mc_amd->mpb); + mc_amd->mpb_size = 0; + } + mc_amd->mpb = xmalloc_bytes(mpbuf->len); + if (mc_amd->mpb == NULL) + return -ENOMEM; + mc_amd->mpb_size = mpbuf->len; + } + memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len); - *offset = off + total_size + 8; + *offset = off + mpbuf->len + 8; return 0; } @@ -254,7 +265,7 @@ static int cpu_request_microcode(int cpu int error = 0; int ret; struct ucode_cpu_info *uci = ucode_cpu_info + cpu; - void *mc; + struct microcode_amd *mc_amd, *mc_old; /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); @@ -275,8 +286,8 @@ static int cpu_request_microcode(int cpu return -EINVAL; } - mc = xmalloc_bytes(UCODE_MAX_SIZE); - if ( mc == NULL ) + mc_amd = xmalloc(struct microcode_amd); + if ( mc_amd == NULL ) { printk(KERN_ERR "microcode: error! " "Can not allocate memory for microcode patch\n"); @@ -284,32 +295,37 @@ static int cpu_request_microcode(int cpu 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) + mc_amd->mpb = NULL; + mc_amd->mpb_size = 0; + while ( (ret = get_next_ucode_from_buffer_amd(mc_amd, buf, size, + &offset)) == 0 ) { - error = microcode_fits(mc, cpu); - if (error != 0) + error = microcode_fits(mc_amd, cpu); + if (error <= 0) continue; error = apply_microcode(cpu); - if (error == 0) + if (error == 0) { + error = 1; break; + } } /* 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); diff -r 548923a4fcf6 -r a063cab704c2 xen/include/asm-x86/microcode.h --- a/xen/include/asm-x86/microcode.h Tue Dec 20 20:50:49 2011 -0500 +++ b/xen/include/asm-x86/microcode.h Fri Dec 23 11:04:57 2011 -0500 @@ -69,8 +69,8 @@ struct microcode_header_amd { } __attribute__((packed)); struct microcode_amd { - struct microcode_header_amd hdr; - unsigned int mpb[0]; + void *mpb; + size_t mpb_size; }; struct cpu_signature {
Keith Coleman
2012-Jan-03 23:19 UTC
Re: [PATCH] Xen 3.4: x86/ucode: fix for AMD Fam15 CPUs
On Tue, Jan 3, 2012 at 5:48 PM, Boris Ostrovsky <boris.ostrovsky@amd.com> wrote:> # HG changeset patch > # User Boris Ostrovsky <boris.ostrovsky@amd.com> > # Date 1324656297 18000 > # Node ID a063cab704c21c7adc2d69c47b50433294f9cd02 > # Parent 548923a4fcf66b51d6d5332f5de575116e2ce67a > Xen 3.4: x86/ucode: fix for AMD Fam15 CPUs > > Remove hardcoded maximum size a microcode patch can have. This is > dynamic now. > > The microcode patch for family15h can be larger than 2048 bytes and > gets silently truncated. > > Signed-off-by: Boris Ostrovsky <boris.ostrovsky@amd.com> > Acked-by: Christoph Egger <Christoph.Egger@amd.com> > xen-unstable changeset: 24412:ca5f588bd203 > xen-unstable date: Thu Dec 15 11:00:09 2011 +0100Thanks! This patch will make the upcoming xen-3.4.4 release. Keith Coleman