static int microcode_resume_match(int cpu, const void *mc) { 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; if ( !microcode_fits(src, cpu) ) return 0; if ( src != mc_amd ) { if ( mc_amd ) { xfree(mc_amd->equiv_cpu_table); xfree(mc_amd->mpb); xfree(mc_amd); } mc_amd = xmalloc(struct microcode_amd); uci->mc.mc_amd = mc_amd; if ( !mc_amd ) return -ENOMEM; mc_amd->equiv_cpu_table = xmalloc_bytes(src->equiv_cpu_table_size); if ( !mc_amd->equiv_cpu_table ) goto err1; mc_amd->mpb = xmalloc_bytes(src->mpb_size); if ( !mc_amd->mpb ) goto err2; mc_amd->equiv_cpu_table_size = src->equiv_cpu_table_size; mc_amd->mpb_size = src->mpb_size; memcpy(mc_amd->mpb, src->mpb, src->mpb_size); memcpy(mc_amd->equiv_cpu_table, src->equiv_cpu_table, src->equiv_cpu_table_size); } return 1; err2: xfree(mc_amd->equiv_cpu_table); err1: xfree(mc_amd); uci->mc.mc_amd = NULL; return -ENOMEM; }
static int cpu_request_microcode(int cpu, const void *buf, size_t bufsize) { struct microcode_amd *mc_amd, *mc_old; size_t offset = bufsize; size_t last_offset, applied_offset = 0; int error = 0; struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); if ( *(const uint32_t *)buf != UCODE_MAGIC ) { printk(KERN_ERR "microcode: Wrong microcode patch file magic\n"); error = -EINVAL; goto out; } mc_amd = xmalloc(struct microcode_amd); if ( !mc_amd ) { printk(KERN_ERR "microcode: Cannot allocate memory for microcode patch\n"); error = -ENOMEM; goto out; } error = install_equiv_cpu_table(mc_amd, buf, &offset); if ( error ) { xfree(mc_amd); printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); error = -EINVAL; goto out; } mc_old = uci->mc.mc_amd; /* implicitely validates uci->mc.mc_valid */ uci->mc.mc_amd = mc_amd; /* * It's possible the data file has multiple matching ucode, * lets keep searching till the latest version */ mc_amd->mpb = NULL; mc_amd->mpb_size = 0; last_offset = offset; while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize, &offset)) == 0 ) { if ( microcode_fits(mc_amd, cpu) ) { error = apply_microcode(cpu); if ( error ) break; applied_offset = last_offset; } last_offset = offset; if ( offset >= bufsize ) break; } /* On success keep the microcode patch for * re-apply on resume. */ if ( applied_offset ) { int ret = get_ucode_from_buffer_amd(mc_amd, buf, bufsize, &applied_offset); if ( ret == 0 ) xfree(mc_old); else error = ret; } if ( !applied_offset || error ) { xfree(mc_amd); uci->mc.mc_amd = mc_old; } out: svm_host_osvw_init(); /* * In some cases we may return an error even if processor's microcode has * been updated. For example, the first patch in a container file is loaded * successfully but subsequent container file processing encounters a * failure. */ return error; }
static int cpu_request_microcode(int cpu, const void *buf, size_t bufsize) { struct microcode_amd *mc_amd, *mc_old; size_t offset = 0; size_t last_offset, applied_offset = 0; int error = 0, save_error = 1; struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); unsigned int current_cpu_id; unsigned int equiv_cpu_id; /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); current_cpu_id = cpuid_eax(0x00000001); if ( *(const uint32_t *)buf != UCODE_MAGIC ) { printk(KERN_ERR "microcode: Wrong microcode patch file magic\n"); error = -EINVAL; goto out; } mc_amd = xmalloc(struct microcode_amd); if ( !mc_amd ) { printk(KERN_ERR "microcode: Cannot allocate memory for microcode patch\n"); error = -ENOMEM; goto out; } /* * Multiple container file support: * 1. check if this container file has equiv_cpu_id match * 2. If not, fast-fwd to next container file */ while ( offset < bufsize ) { error = install_equiv_cpu_table(mc_amd, buf, &offset); if ( error ) { printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); break; } /* * Could happen as we advance 'offset' early * in install_equiv_cpu_table */ if ( offset > bufsize ) { printk(KERN_ERR "microcode: Microcode buffer overrun\n"); error = -EINVAL; break; } if ( find_equiv_cpu_id(mc_amd->equiv_cpu_table, current_cpu_id, &equiv_cpu_id) ) break; error = container_fast_forward(buf, bufsize - offset, &offset); if ( error == -ENODATA ) { ASSERT(offset == bufsize); break; } if ( error ) { printk(KERN_ERR "microcode: CPU%d incorrect or corrupt container file\n" "microcode: Failed to update patch level. " "Current lvl:%#x\n", cpu, uci->cpu_sig.rev); break; } } if ( error ) { xfree(mc_amd); goto out; } mc_old = uci->mc.mc_amd; /* implicitely validates uci->mc.mc_valid */ uci->mc.mc_amd = mc_amd; /* * It's possible the data file has multiple matching ucode, * lets keep searching till the latest version */ mc_amd->mpb = NULL; mc_amd->mpb_size = 0; last_offset = offset; while ( (error = get_ucode_from_buffer_amd(mc_amd, buf, bufsize, &offset)) == 0 ) { if ( microcode_fits(mc_amd, cpu) ) { error = apply_microcode(cpu); if ( error ) break; applied_offset = last_offset; } last_offset = offset; if ( offset >= bufsize ) break; /* * 1. Given a situation where multiple containers exist and correct * patch lives on a container that is not the last container. * 2. We match equivalent ids using find_equiv_cpu_id() from the * earlier while() (On this case, matches on earlier container * file and we break) * 3. Proceed to while ( (error = get_ucode_from_buffer_amd(mc_amd, * buf, bufsize,&offset)) == 0 ) * 4. Find correct patch using microcode_fits() and apply the patch * (Assume: apply_microcode() is successful) * 5. The while() loop from (3) continues to parse the binary as * there is a subsequent container file, but... * 6. ...a correct patch can only be on one container and not on any * subsequent ones. (Refer docs for more info) Therefore, we * don't have to parse a subsequent container. So, we can abort * the process here. * 7. This ensures that we retain a success value (= 0) to 'error' * before if ( mpbuf->type != UCODE_UCODE_TYPE ) evaluates to * false and returns -EINVAL. */ if ( offset + SECTION_HDR_SIZE <= bufsize && *(const uint32_t *)(buf + offset) == UCODE_MAGIC ) break; } /* On success keep the microcode patch for * re-apply on resume. */ if ( applied_offset ) { save_error = get_ucode_from_buffer_amd( mc_amd, buf, bufsize, &applied_offset); if ( save_error ) error = save_error; } if ( save_error ) { xfree(mc_amd); uci->mc.mc_amd = mc_old; } else xfree(mc_old); out: svm_host_osvw_init(); /* * In some cases we may return an error even if processor's microcode has * been updated. For example, the first patch in a container file is loaded * successfully but subsequent container file processing encounters a * failure. */ return error; }
static int cpu_request_microcode(int cpu, const void *buf, size_t size) { const uint32_t *buf_pos; unsigned long offset = 0; int error; struct ucode_cpu_info *uci = &per_cpu(ucode_cpu_info, cpu); void *mc; size_t mc_size; /* We should bind the task to the CPU */ BUG_ON(cpu != raw_smp_processor_id()); buf_pos = (const uint32_t *)buf; if ( buf_pos[0] != UCODE_MAGIC ) { printk(KERN_ERR "microcode: error! Wrong " "microcode patch file magic\n"); return -EINVAL; } error = install_equiv_cpu_table(buf, (uint32_t)(buf_pos[2]), &offset); if ( error ) { printk(KERN_ERR "microcode: installing equivalent cpu table failed\n"); return -EINVAL; } /* Size of 1st microcode patch in bytes */ mc_size = buf_pos[offset / sizeof(*buf_pos) + 1]; mc = xmalloc_bytes(mc_size); if ( mc == NULL ) { printk(KERN_ERR "microcode: error! " "Can not allocate memory for microcode patch\n"); error = -ENOMEM; goto out; } /* implicitely validates uci->mc.mc_valid */ uci->mc.mc_amd = mc; /* * It's possible the data file has multiple matching ucode, * lets keep searching till the latest version */ while ( (error = get_next_ucode_from_buffer_amd(&mc, &mc_size, buf, size, &offset)) == 0 ) { uci->mc.mc_amd = mc; error = microcode_fits(mc, cpu); if (error <= 0) continue; error = apply_microcode(cpu); if (error == 0) { error = 1; break; } } /* On success keep the microcode patch for * re-apply on resume. */ if ( error <= 0 ) { xfree(mc); mc = NULL; } else error = 0; uci->mc.mc_amd = mc; out: xfree(equiv_cpu_table); equiv_cpu_table = NULL; return error; }