📄 microcode.c
字号:
while (cursor + MC_HEADER_SIZE < user_buffer_size) { microcode_header_t mc_header; void *newmc = NULL; int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size; if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) { printk(KERN_ERR "microcode: error! Can not read user data\n"); error = -EFAULT; goto out; } total_size = get_totalsize(&mc_header); if (cursor + total_size > user_buffer_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; } data_size = get_datasize(&mc_header); if (data_size + MC_HEADER_SIZE > total_size) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; } if (mc_header.ldrver != 1 || mc_header.hdrver != 1) { printk(KERN_ERR "microcode: error! Unknown microcode update format\n"); error = -EINVAL; goto out; } for_each_online_cpu(cpu_num) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf)) mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum); } ext_table_size = total_size - (MC_HEADER_SIZE + data_size); if (ext_table_size) { struct extended_sigtable ext_header; struct extended_signature ext_sig; int ext_sigcount; if ((ext_table_size < EXT_HEADER_SIZE) || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EINVAL; goto out; } if (copy_from_user(&ext_header, user_buffer + cursor + MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) { printk(KERN_ERR "microcode: error! Can not read user data\n"); error = -EFAULT; goto out; } if (ext_table_size != exttable_size(&ext_header)) { printk(KERN_ERR "microcode: error! Bad data in microcode data file\n"); error = -EFAULT; goto out; } ext_sigcount = ext_header.count; for (i = 0; i < ext_sigcount; i++) { if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) { printk(KERN_ERR "microcode: error! Can not read user data\n"); error = -EFAULT; goto out; } for_each_online_cpu(cpu_num) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) { mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum); } } } } /* now check if any cpu has matched */ allocated_flag = 0; sum = 0; for_each_online_cpu(cpu_num) { if (ucode_cpu_info[cpu_num].err == MC_MARKED) { struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (!allocated_flag) { allocated_flag = 1; newmc = vmalloc(total_size); if (!newmc) { printk(KERN_ERR "microcode: error! Can not allocate memory\n"); error = -ENOMEM; goto out; } if (copy_from_user(newmc + MC_HEADER_SIZE, user_buffer + cursor + MC_HEADER_SIZE, total_size - MC_HEADER_SIZE)) { printk(KERN_ERR "microcode: error! Can not read user data\n"); vfree(newmc); error = -EFAULT; goto out; } memcpy(newmc, &mc_header, MC_HEADER_SIZE); /* check extended table checksum */ if (ext_table_size) { int ext_table_sum = 0; int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size); i = ext_table_size / DWSIZE; while (i--) ext_table_sum += ext_tablep[i]; if (ext_table_sum) { printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n"); vfree(newmc); error = -EINVAL; goto out; } } /* calculate the checksum */ i = (MC_HEADER_SIZE + data_size) / DWSIZE; while (i--) sum += ((int *)newmc)[i]; sum -= (mc_header.sig + mc_header.pf + mc_header.cksum); } ucode_cpu_info[cpu_num].mc = newmc; ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */ if (sum + uci->sig + uci->pf + uci->cksum != 0) { printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num); error = -EINVAL; goto out; } } } cursor += total_size; /* goto the next update patch */ } /* end of while */out: return error;}static void do_update_one (void * unused){ unsigned long flags; unsigned int val[2]; int cpu_num = smp_processor_id(); struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num; if (uci->mc == NULL) { if (verbose) { if (uci->err == MC_SUCCESS) printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n", cpu_num, uci->rev); else printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num); } return; } /* serialize access to the physical write to MSR 0x79 */ spin_lock_irqsave(µcode_update_lock, flags); /* write microcode via MSR 0x79 */ wrmsr(MSR_IA32_UCODE_WRITE, (unsigned long) uci->mc->bits, (unsigned long) uci->mc->bits >> 16 >> 16); wrmsr(MSR_IA32_UCODE_REV, 0, 0); /* see notes above for revision 1.07. Apparent chip bug */ sync_core(); /* get the current revision from MSR 0x8B */ rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]); /* notify the caller of success on this cpu */ uci->err = MC_SUCCESS; spin_unlock_irqrestore(µcode_update_lock, flags); printk(KERN_INFO "microcode: CPU%d updated from revision " "0x%x to 0x%x, date = %08x \n", cpu_num, uci->rev, val[1], uci->mc->hdr.date); return;}static int do_microcode_update (void){ int i, error; if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) { printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); error = -EIO; goto out; } if ((error = find_matching_ucodes())) { printk(KERN_ERR "microcode: Error in the microcode data\n"); goto out_free; } if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) { printk(KERN_ERR "microcode: Error! Could not run on all processors\n"); error = -EIO; }out_free: for_each_online_cpu(i) { if (ucode_cpu_info[i].mc) { int j; void *tmp = ucode_cpu_info[i].mc; vfree(tmp); for_each_online_cpu(j) { if (ucode_cpu_info[j].mc == tmp) ucode_cpu_info[j].mc = NULL; } } if (ucode_cpu_info[i].err == MC_IGNORED && verbose) printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision" " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev); }out: return error;}int microcode_update(XEN_GUEST_HANDLE(void) buf, unsigned long len){ int ret; if (len != (typeof(user_buffer_size))len) { printk(KERN_ERR "microcode: too much data\n"); return -E2BIG; } mutex_lock(µcode_mutex); user_buffer = buf.p; user_buffer_size = len; ret = do_microcode_update(); mutex_unlock(µcode_mutex); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -