microcode.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 531 行 · 第 1/2 页

C
531
字号
		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 (cpu_num = 0; cpu_num < smp_num_cpus; cpu_num++) {					struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;					if (uci->err != MC_NOTFOUND) /* already found a match or not an online cpu*/						continue;					if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->pf)) {						mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);					}				}			}		}		/* now check if any cpu has matched */		for (cpu_num = 0, allocated_flag = 0, sum = 0; cpu_num < smp_num_cpus; 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_tablep;						int ext_table_sum = 0;						i = ext_table_size / DWSIZE;						ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);						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) {		printk(KERN_INFO "microcode: No suitable data for cpu %d\n", cpu_num);		return;	}	/* serialize access to the physical write to MSR 0x79 */	spin_lock_irqsave(&microcode_update_lock, flags);          	/* write microcode via MSR 0x79 */	wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(uci->mc->bits), 0);	wrmsr(MSR_IA32_UCODE_REV, 0, 0);	__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");	/* 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(&microcode_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 (smp_call_function(collect_cpu_info, NULL, 1, 1) != 0) {		printk(KERN_ERR "microcode: Error! Could not run on all processors\n");		error = -EIO;		goto out;	}	collect_cpu_info(NULL);	if ((error = find_matching_ucodes())) {		printk(KERN_ERR "microcode: Error in the microcode data\n");		goto out_free;	}	if (smp_call_function(do_update_one, NULL, 1, 1) != 0) {		printk(KERN_ERR "microcode: Error! Could not run on all processors\n");		error = -EIO;	}	do_update_one(NULL);out_free:	for (i = 0; i < smp_num_cpus; i++) {		if (ucode_cpu_info[i].mc) {			int j;			void *tmp = ucode_cpu_info[i].mc;			vfree(tmp);			for (j = i; j < smp_num_cpus; j++) {				if (ucode_cpu_info[j].mc == tmp)					ucode_cpu_info[j].mc = NULL;			}		}	}out:	return error;}static ssize_t microcode_write (struct file *file, const char *buf, size_t len, loff_t *ppos){	ssize_t ret;	if (len < DEFAULT_UCODE_TOTALSIZE) {		printk(KERN_ERR "microcode: not enough data\n"); 		return -EINVAL;	}	if ((len >> PAGE_SHIFT) > num_physpages) {		printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);		return -EINVAL;	}	down(&microcode_sem);	user_buffer = (void *) buf;	user_buffer_size = (int) len;	ret = do_microcode_update();	if (!ret)		ret = (ssize_t)len;	up(&microcode_sem);	return ret;}static int microcode_ioctl (struct inode *inode, struct file *file, 		unsigned int cmd, unsigned long arg){	switch (cmd) {		/* 		 *  XXX: will be removed after microcode_ctl 		 *  is updated to ignore failure of this ioctl()		 */		case MICROCODE_IOCFREE:			return 0;		default:			return -EINVAL;	}	return -EINVAL;}/* shared between misc device and devfs regular file */static struct file_operations microcode_fops = {	.owner		= THIS_MODULE,	.write		= microcode_write,	.ioctl		= microcode_ioctl,	.open		= microcode_open,};static struct miscdevice microcode_dev = {	.minor		= MICROCODE_MINOR,	.name		= "microcode",	.fops		= &microcode_fops,};static devfs_handle_t devfs_handle;static int __init microcode_init (void){	int error;	error = misc_register(&microcode_dev);	if (error)		printk(KERN_ERR			"microcode: can't misc_register on minor=%d\n",			MICROCODE_MINOR);	devfs_handle = devfs_register(NULL, "cpu/microcode",			DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUSR | S_IWUSR, 			&microcode_fops, NULL);	if (devfs_handle == NULL && error) {		printk(KERN_ERR "microcode: failed to devfs_register()\n");		goto out;	}	error = 0;	printk(KERN_INFO 		"IA-32 Microcode Update Driver: v"		MICROCODE_VERSION " <tigran@veritas.com>\n");out:	return error;}static void __exit microcode_exit (void){	misc_deregister(&microcode_dev);	devfs_unregister(devfs_handle);	printk(KERN_INFO "IA-32 Microcode Update Driver v" 		MICROCODE_VERSION " unregistered\n");}module_init(microcode_init)module_exit(microcode_exit)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?