xcp-1.6-updates/xen-4.1.hg

changeset 23214:e29b7691fefc

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: Christoph Egger <Christoph.Egger@amd.com>
Backport from xen-unstable changeset 24411:ca5f588bd203 to Xen 4.1
author Christoph Egger <Christoph.Egger@amd.com>
date Sun Jan 15 22:08:13 2012 +0000 (2012-01-15)
parents 22ea8496051d
children 2fb706161c09
files xen/arch/x86/microcode_amd.c xen/include/asm-x86/microcode.h
line diff
     1.1 --- a/xen/arch/x86/microcode_amd.c	Tue Jan 10 17:09:26 2012 +0000
     1.2 +++ b/xen/arch/x86/microcode_amd.c	Sun Jan 15 22:08:13 2012 +0000
     1.3 @@ -33,11 +33,11 @@
     1.4  #define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
     1.5  #define UCODE_UCODE_TYPE           0x00000001
     1.6  
     1.7 -#define UCODE_MAX_SIZE          (2048)
     1.8 -#define DEFAULT_UCODE_DATASIZE  (896)
     1.9 -#define MC_HEADER_SIZE          (sizeof(struct microcode_header_amd))
    1.10 -#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
    1.11 -#define DWSIZE                  (sizeof(uint32_t))
    1.12 +struct mpbhdr {
    1.13 +    uint32_t type;
    1.14 +    uint32_t len;
    1.15 +    uint8_t data[];
    1.16 +};
    1.17  
    1.18  /* serialize access to the physical write */
    1.19  static DEFINE_SPINLOCK(microcode_update_lock);
    1.20 @@ -65,10 +65,10 @@ static int collect_cpu_info(int cpu, str
    1.21      return 0;
    1.22  }
    1.23  
    1.24 -static int microcode_fits(void *mc, int cpu)
    1.25 +static int microcode_fits(const struct microcode_amd *mc_amd, int cpu)
    1.26  {
    1.27      struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
    1.28 -    struct microcode_header_amd *mc_header = mc;
    1.29 +    struct microcode_header_amd *mc_header = mc_amd->mpb;
    1.30      unsigned int current_cpu_id;
    1.31      unsigned int equiv_cpu_id = 0x0;
    1.32      unsigned int i;
    1.33 @@ -97,9 +97,9 @@ static int microcode_fits(void *mc, int 
    1.34  
    1.35      if ( !equiv_cpu_id )
    1.36      {
    1.37 -        printk(KERN_ERR "microcode: CPU%d cpu_id "
    1.38 +        printk(KERN_INFO "microcode: CPU%d cpu_id "
    1.39                 "not found in equivalent cpu table\n", cpu);
    1.40 -        return -EINVAL;
    1.41 +        return 0;
    1.42      }
    1.43  
    1.44      if ( (mc_header->processor_rev_id) != equiv_cpu_id )
    1.45 @@ -111,14 +111,14 @@ static int microcode_fits(void *mc, int 
    1.46      }
    1.47  
    1.48      if ( mc_header->patch_id <= uci->cpu_sig.rev )
    1.49 -        return -EINVAL;
    1.50 +        return 0;
    1.51  
    1.52      printk(KERN_INFO "microcode: CPU%d found a matching microcode "
    1.53             "update with version 0x%x (current=0x%x)\n",
    1.54             cpu, mc_header->patch_id, uci->cpu_sig.rev);
    1.55  
    1.56  out:
    1.57 -    return 0;
    1.58 +    return 1;
    1.59  }
    1.60  
    1.61  static int apply_microcode(int cpu)
    1.62 @@ -127,16 +127,21 @@ static int apply_microcode(int cpu)
    1.63      struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
    1.64      uint32_t rev;
    1.65      struct microcode_amd *mc_amd = uci->mc.mc_amd;
    1.66 +    struct microcode_header_amd *hdr;
    1.67  
    1.68      /* We should bind the task to the CPU */
    1.69      BUG_ON(raw_smp_processor_id() != cpu);
    1.70  
    1.71      if ( mc_amd == NULL )
    1.72 -        return -EINVAL;
    1.73 +       return -EINVAL;
    1.74 +
    1.75 +    hdr = mc_amd->mpb;
    1.76 +    if ( hdr == NULL )
    1.77 +       return -EINVAL;
    1.78  
    1.79      spin_lock_irqsave(&microcode_update_lock, flags);
    1.80  
    1.81 -    wrmsrl(MSR_AMD_PATCHLOADER, (unsigned long)&mc_amd->hdr.data_code);
    1.82 +    wrmsrl(MSR_AMD_PATCHLOADER, (unsigned long)hdr);
    1.83  
    1.84      /* get patch id after patching */
    1.85      rdmsrl(MSR_AMD_PATCHLEVEL, rev);
    1.86 @@ -144,61 +149,67 @@ static int apply_microcode(int cpu)
    1.87      spin_unlock_irqrestore(&microcode_update_lock, flags);
    1.88  
    1.89      /* check current patch id and patch's id for match */
    1.90 -    if ( rev != mc_amd->hdr.patch_id )
    1.91 +    if ( rev != hdr->patch_id )
    1.92      {
    1.93          printk(KERN_ERR "microcode: CPU%d update from revision "
    1.94                 "0x%x to 0x%x failed\n", cpu,
    1.95 -               mc_amd->hdr.patch_id, rev);
    1.96 +               hdr->patch_id, rev);
    1.97          return -EIO;
    1.98      }
    1.99  
   1.100      printk("microcode: CPU%d updated from revision "
   1.101             "0x%x to 0x%x \n",
   1.102 -           cpu, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
   1.103 +           cpu, uci->cpu_sig.rev, hdr->patch_id);
   1.104  
   1.105      uci->cpu_sig.rev = rev;
   1.106  
   1.107      return 0;
   1.108  }
   1.109  
   1.110 -static int get_next_ucode_from_buffer_amd(void *mc, const void *buf,
   1.111 -                                         size_t size, unsigned long *offset)
   1.112 +static int get_next_ucode_from_buffer_amd(struct microcode_amd *mc_amd,
   1.113 +                                         const void *buf, size_t bufsize,
   1.114 +                                         unsigned long *offset)
   1.115  {
   1.116 -    struct microcode_header_amd *mc_header;
   1.117 -    size_t total_size;
   1.118      const uint8_t *bufp = buf;
   1.119      unsigned long off;
   1.120 +    const struct mpbhdr *mpbuf;
   1.121  
   1.122      off = *offset;
   1.123  
   1.124      /* No more data */
   1.125 -    if ( off >= size )
   1.126 +    if ( off >= bufsize )
   1.127          return 1;
   1.128  
   1.129 -    if ( bufp[off] != UCODE_UCODE_TYPE )
   1.130 +    mpbuf = (const struct mpbhdr *)&bufp[off];
   1.131 +    if ( mpbuf->type != UCODE_UCODE_TYPE )
   1.132      {
   1.133          printk(KERN_ERR "microcode: error! "
   1.134                 "Wrong microcode payload type field\n");
   1.135          return -EINVAL;
   1.136      }
   1.137  
   1.138 -    mc_header = (struct microcode_header_amd *)(&bufp[off+8]);
   1.139 -
   1.140 -    total_size = (unsigned long) (bufp[off+4] + (bufp[off+5] << 8));
   1.141 +    printk(KERN_INFO "microcode: size %lu, total_size %u, offset %ld\n",
   1.142 +           bufsize, mpbuf->len, off);
   1.143  
   1.144 -    printk(KERN_INFO "microcode: size %lu, total_size %lu, offset %ld\n",
   1.145 -           (unsigned long)size, total_size, off);
   1.146 -
   1.147 -    if ( (off + total_size) > size )
   1.148 +    if ( (off + mpbuf->len) > bufsize )
   1.149      {
   1.150          printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
   1.151          return -EINVAL;
   1.152      }
   1.153  
   1.154 -    memset(mc, 0, UCODE_MAX_SIZE);
   1.155 -    memcpy(mc, (const void *)(&bufp[off + 8]), total_size);
   1.156 +    if (mc_amd->mpb_size < mpbuf->len) {
   1.157 +        if (mc_amd->mpb) {
   1.158 +            xfree(mc_amd->mpb);
   1.159 +            mc_amd->mpb_size = 0;
   1.160 +        }
   1.161 +        mc_amd->mpb = xmalloc_bytes(mpbuf->len);
   1.162 +        if (mc_amd->mpb == NULL)
   1.163 +            return -ENOMEM;
   1.164 +        mc_amd->mpb_size = mpbuf->len;
   1.165 +    }
   1.166 +    memcpy(mc_amd->mpb, mpbuf->data, mpbuf->len);
   1.167  
   1.168 -    *offset = off + total_size + 8;
   1.169 +    *offset = off + mpbuf->len + 8;
   1.170  
   1.171      return 0;
   1.172  }
   1.173 @@ -253,7 +264,7 @@ static int cpu_request_microcode(int cpu
   1.174      int error = 0;
   1.175      int ret;
   1.176      struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu);
   1.177 -    void *mc;
   1.178 +    struct microcode_amd *mc_amd, *mc_old;
   1.179  
   1.180      /* We should bind the task to the CPU */
   1.181      BUG_ON(cpu != raw_smp_processor_id());
   1.182 @@ -274,8 +285,8 @@ static int cpu_request_microcode(int cpu
   1.183          return -EINVAL;
   1.184      }
   1.185  
   1.186 -    mc = xmalloc_bytes(UCODE_MAX_SIZE);
   1.187 -    if ( mc == NULL )
   1.188 +    mc_amd = xmalloc(struct microcode_amd);
   1.189 +    if ( mc_amd == NULL )
   1.190      {
   1.191          printk(KERN_ERR "microcode: error! "
   1.192                 "Can not allocate memory for microcode patch\n");
   1.193 @@ -283,32 +294,37 @@ static int cpu_request_microcode(int cpu
   1.194          goto out;
   1.195      }
   1.196  
   1.197 +    mc_old = uci->mc.mc_amd;
   1.198      /* implicitely validates uci->mc.mc_valid */
   1.199 -    uci->mc.mc_amd = mc;
   1.200 +    uci->mc.mc_amd = mc_amd;
   1.201  
   1.202      /*
   1.203       * It's possible the data file has multiple matching ucode,
   1.204       * lets keep searching till the latest version
   1.205       */
   1.206 -    while ( (ret = get_next_ucode_from_buffer_amd(mc, buf, size, &offset)) == 0)
   1.207 +    mc_amd->mpb = NULL;
   1.208 +    mc_amd->mpb_size = 0;
   1.209 +    while ( (ret = get_next_ucode_from_buffer_amd(mc_amd, buf, size,
   1.210 +                                                  &offset)) == 0)
   1.211      {
   1.212 -        error = microcode_fits(mc, cpu);
   1.213 -        if (error != 0)
   1.214 +        error = microcode_fits(mc_amd, cpu);
   1.215 +        if (error <= 0)
   1.216              continue;
   1.217  
   1.218          error = apply_microcode(cpu);
   1.219 -        if (error == 0)
   1.220 +        if (error == 0) {
   1.221 +            error = 1;
   1.222              break;
   1.223 +        }
   1.224      }
   1.225  
   1.226      /* On success keep the microcode patch for
   1.227       * re-apply on resume.
   1.228       */
   1.229 -    if (error) {
   1.230 -        xfree(mc);
   1.231 -        mc = NULL;
   1.232 +    if (error == 0) {
   1.233 +        xfree(mc_old);
   1.234 +        return 0;
   1.235      }
   1.236 -    uci->mc.mc_amd = mc;
   1.237  
   1.238  out:
   1.239      xfree(equiv_cpu_table);
     2.1 --- a/xen/include/asm-x86/microcode.h	Tue Jan 10 17:09:26 2012 +0000
     2.2 +++ b/xen/include/asm-x86/microcode.h	Sun Jan 15 22:08:13 2012 +0000
     2.3 @@ -71,8 +71,8 @@ struct microcode_header_amd {
     2.4  } __attribute__((packed));
     2.5  
     2.6  struct microcode_amd {
     2.7 -    struct microcode_header_amd hdr;
     2.8 -    unsigned int mpb[0];
     2.9 +    void *mpb;
    2.10 +    size_t mpb_size;
    2.11  };
    2.12  
    2.13  struct cpu_signature {