⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 microcode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;}static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos){	ssize_t ret;	if ((len >> PAGE_SHIFT) > num_physpages) {		printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);		return -EINVAL;	}	lock_cpu_hotplug();	mutex_lock(&microcode_mutex);	user_buffer = (void __user *) buf;	user_buffer_size = (int) len;	ret = do_microcode_update();	if (!ret)		ret = (ssize_t)len;	mutex_unlock(&microcode_mutex);	unlock_cpu_hotplug();	return ret;}static const struct file_operations microcode_fops = {	.owner		= THIS_MODULE,	.write		= microcode_write,	.open		= microcode_open,};static struct miscdevice microcode_dev = {	.minor		= MICROCODE_MINOR,	.name		= "microcode",	.fops		= &microcode_fops,};static int __init microcode_dev_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);		return error;	}	return 0;}static void microcode_dev_exit (void){	misc_deregister(&microcode_dev);}MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);#else#define microcode_dev_init() 0#define microcode_dev_exit() do { } while(0)#endifstatic long get_next_ucode_from_buffer(void **mc, void *buf,	unsigned long size, long offset){	microcode_header_t *mc_header;	unsigned long total_size;	/* No more data */	if (offset >= size)		return 0;	mc_header = (microcode_header_t *)(buf + offset);	total_size = get_totalsize(mc_header);	if (offset + total_size > size) {		printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");		return -EINVAL;	}	*mc = vmalloc(total_size);	if (!*mc) {		printk(KERN_ERR "microcode: error! Can not allocate memory\n");		return -ENOMEM;	}	memcpy(*mc, buf + offset, total_size);	return offset + total_size;}/* fake device for request_firmware */static struct platform_device *microcode_pdev;static int cpu_request_microcode(int cpu){	char name[30];	struct cpuinfo_x86 *c = &cpu_data(cpu);	const struct firmware *firmware;	void *buf;	unsigned long size;	long offset = 0;	int error;	void *mc;	/* We should bind the task to the CPU */	BUG_ON(cpu != raw_smp_processor_id());	sprintf(name,"intel-ucode/%02x-%02x-%02x",		c->x86, c->x86_model, c->x86_mask);	error = request_firmware(&firmware, name, &microcode_pdev->dev);	if (error) {		pr_debug("ucode data file %s load failed\n", name);		return error;	}	buf = (void *)firmware->data;	size = firmware->size;	while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))			> 0) {		error = microcode_sanity_check(mc);		if (error)			break;		error = get_maching_microcode(mc, cpu);		if (error < 0)			break;		/*		 * It's possible the data file has multiple matching ucode,		 * lets keep searching till the latest version		 */		if (error == 1) {			apply_microcode(cpu);			error = 0;		}		vfree(mc);	}	if (offset > 0)		vfree(mc);	if (offset < 0)		error = offset;	release_firmware(firmware);	return error;}static int apply_microcode_check_cpu(int cpu){	struct cpuinfo_x86 *c = &cpu_data(cpu);	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;	cpumask_t old;	unsigned int val[2];	int err = 0;	/* Check if the microcode is available */	if (!uci->mc)		return 0;	old = current->cpus_allowed;	set_cpus_allowed(current, cpumask_of_cpu(cpu));	/* Check if the microcode we have in memory matches the CPU */	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||	    cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))		err = -EINVAL;	if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {		/* get processor flags from MSR 0x17 */		rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);		if (uci->pf != (1 << ((val[1] >> 18) & 7)))			err = -EINVAL;	}	if (!err) {		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]);		if (uci->rev != val[1])			err = -EINVAL;	}	if (!err)		apply_microcode(cpu);	else		printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"			" sig=0x%x, pf=0x%x, rev=0x%x\n",			cpu, uci->sig, uci->pf, uci->rev);	set_cpus_allowed(current, old);	return err;}static void microcode_init_cpu(int cpu, int resume){	cpumask_t old;	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;	old = current->cpus_allowed;	set_cpus_allowed(current, cpumask_of_cpu(cpu));	mutex_lock(&microcode_mutex);	collect_cpu_info(cpu);	if (uci->valid && system_state == SYSTEM_RUNNING && !resume)		cpu_request_microcode(cpu);	mutex_unlock(&microcode_mutex);	set_cpus_allowed(current, old);}static void microcode_fini_cpu(int cpu){	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;	mutex_lock(&microcode_mutex);	uci->valid = 0;	vfree(uci->mc);	uci->mc = NULL;	mutex_unlock(&microcode_mutex);}static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz){	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;	char *end;	unsigned long val = simple_strtoul(buf, &end, 0);	int err = 0;	int cpu = dev->id;	if (end == buf)		return -EINVAL;	if (val == 1) {		cpumask_t old;		old = current->cpus_allowed;		lock_cpu_hotplug();		set_cpus_allowed(current, cpumask_of_cpu(cpu));		mutex_lock(&microcode_mutex);		if (uci->valid)			err = cpu_request_microcode(cpu);		mutex_unlock(&microcode_mutex);		unlock_cpu_hotplug();		set_cpus_allowed(current, old);	}	if (err)		return err;	return sz;}static ssize_t version_show(struct sys_device *dev, char *buf){	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;	return sprintf(buf, "0x%x\n", uci->rev);}static ssize_t pf_show(struct sys_device *dev, char *buf){	struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;	return sprintf(buf, "0x%x\n", uci->pf);}static SYSDEV_ATTR(reload, 0200, NULL, reload_store);static SYSDEV_ATTR(version, 0400, version_show, NULL);static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);static struct attribute *mc_default_attrs[] = {	&attr_reload.attr,	&attr_version.attr,	&attr_processor_flags.attr,	NULL};static struct attribute_group mc_attr_group = {	.attrs = mc_default_attrs,	.name = "microcode",};static int __mc_sysdev_add(struct sys_device *sys_dev, int resume){	int err, cpu = sys_dev->id;	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;	if (!cpu_online(cpu))		return 0;	pr_debug("Microcode:CPU %d added\n", cpu);	memset(uci, 0, sizeof(*uci));	err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);	if (err)		return err;	microcode_init_cpu(cpu, resume);	return 0;}static int mc_sysdev_add(struct sys_device *sys_dev){	return __mc_sysdev_add(sys_dev, 0);}static int mc_sysdev_remove(struct sys_device *sys_dev){	int cpu = sys_dev->id;	if (!cpu_online(cpu))		return 0;	pr_debug("Microcode:CPU %d removed\n", cpu);	microcode_fini_cpu(cpu);	sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);	return 0;}static int mc_sysdev_resume(struct sys_device *dev){	int cpu = dev->id;	if (!cpu_online(cpu))		return 0;	pr_debug("Microcode:CPU %d resumed\n", cpu);	/* only CPU 0 will apply ucode here */	apply_microcode(0);	return 0;}static struct sysdev_driver mc_sysdev_driver = {	.add = mc_sysdev_add,	.remove = mc_sysdev_remove,	.resume = mc_sysdev_resume,};static __cpuinit intmc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu){	unsigned int cpu = (unsigned long)hcpu;	struct sys_device *sys_dev;	sys_dev = get_cpu_sysdev(cpu);	switch (action) {	case CPU_UP_CANCELED_FROZEN:		/* The CPU refused to come up during a system resume */		microcode_fini_cpu(cpu);		break;	case CPU_ONLINE:	case CPU_DOWN_FAILED:		mc_sysdev_add(sys_dev);		break;	case CPU_ONLINE_FROZEN:		/* System-wide resume is in progress, try to apply microcode */		if (apply_microcode_check_cpu(cpu)) {			/* The application of microcode failed */			microcode_fini_cpu(cpu);			__mc_sysdev_add(sys_dev, 1);			break;		}	case CPU_DOWN_FAILED_FROZEN:		if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))			printk(KERN_ERR "Microcode: Failed to create the sysfs "				"group for CPU%d\n", cpu);		break;	case CPU_DOWN_PREPARE:		mc_sysdev_remove(sys_dev);		break;	case CPU_DOWN_PREPARE_FROZEN:		/* Suspend is in progress, only remove the interface */		sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);		break;	}	return NOTIFY_OK;}static struct notifier_block __cpuinitdata mc_cpu_notifier = {	.notifier_call = mc_cpu_callback,};static int __init microcode_init (void){	int error;	error = microcode_dev_init();	if (error)		return error;	microcode_pdev = platform_device_register_simple("microcode", -1,							 NULL, 0);	if (IS_ERR(microcode_pdev)) {		microcode_dev_exit();		return PTR_ERR(microcode_pdev);	}	lock_cpu_hotplug();	error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);	unlock_cpu_hotplug();	if (error) {		microcode_dev_exit();		platform_device_unregister(microcode_pdev);		return error;	}	register_hotcpu_notifier(&mc_cpu_notifier);	printk(KERN_INFO 		"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");	return 0;}static void __exit microcode_exit (void){	microcode_dev_exit();	unregister_hotcpu_notifier(&mc_cpu_notifier);	lock_cpu_hotplug();	sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);	unlock_cpu_hotplug();	platform_device_unregister(microcode_pdev);}module_init(microcode_init)module_exit(microcode_exit)

⌨️ 快捷键说明

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