efivars.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 756 行 · 第 1/2 页

C
756
字号
	return ret;}static struct sysfs_ops efivar_attr_ops = {	.show = efivar_attr_show,	.store = efivar_attr_store,};static void efivar_release(struct kobject *kobj){	struct efivar_entry *var = container_of(kobj, struct efivar_entry, kobj);	spin_lock(&efivars_lock);	list_del(&var->list);	spin_unlock(&efivars_lock);	kfree(var);}static EFIVAR_ATTR(guid, 0400, efivar_guid_read, NULL);static EFIVAR_ATTR(attributes, 0400, efivar_attr_read, NULL);static EFIVAR_ATTR(size, 0400, efivar_size_read, NULL);static EFIVAR_ATTR(data, 0400, efivar_data_read, NULL);static EFIVAR_ATTR(raw_var, 0600, efivar_show_raw, efivar_store_raw);static struct attribute *def_attrs[] = {	&efivar_attr_guid.attr,	&efivar_attr_size.attr,	&efivar_attr_attributes.attr,	&efivar_attr_data.attr,	&efivar_attr_raw_var.attr,	NULL,};static struct kobj_type ktype_efivar = {	.release = efivar_release,	.sysfs_ops = &efivar_attr_ops,	.default_attrs = def_attrs,};static ssize_tdummy(struct subsystem *sub, char *buf){	return -ENODEV;}static inline voidefivar_unregister(struct efivar_entry *var){	kobject_unregister(&var->kobj);}static ssize_tefivar_create(struct subsystem *sub, const char *buf, size_t count){	struct efi_variable *new_var = (struct efi_variable *)buf;	struct efivar_entry *search_efivar = NULL;	unsigned long strsize1, strsize2;	struct list_head *pos, *n;	efi_status_t status = EFI_NOT_FOUND;	int found = 0;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	spin_lock(&efivars_lock);	/*	 * Does this variable already exist?	 */	list_for_each_safe(pos, n, &efivar_list) {		search_efivar = get_efivar_entry(pos);		strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);		strsize2 = utf8_strsize(new_var->VariableName, 1024);		if (strsize1 == strsize2 &&			!memcmp(&(search_efivar->var.VariableName),				new_var->VariableName, strsize1) &&			!efi_guidcmp(search_efivar->var.VendorGuid,				new_var->VendorGuid)) {			found = 1;			break;		}	}	if (found) {		spin_unlock(&efivars_lock);		return -EINVAL;	}	/* now *really* create the variable via EFI */	status = efi.set_variable(new_var->VariableName,			&new_var->VendorGuid,			new_var->Attributes,			new_var->DataSize,			new_var->Data);	if (status != EFI_SUCCESS) {		printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",			status);		spin_unlock(&efivars_lock);		return -EIO;	}	spin_unlock(&efivars_lock);	/* Create the entry in sysfs.  Locking is not required here */	status = efivar_create_sysfs_entry(utf8_strsize(new_var->VariableName,			1024), new_var->VariableName, &new_var->VendorGuid);	if (status) {		printk(KERN_WARNING "efivars: variable created, but sysfs entry wasn't.\n");	}	return count;}static ssize_tefivar_delete(struct subsystem *sub, const char *buf, size_t count){	struct efi_variable *del_var = (struct efi_variable *)buf;	struct efivar_entry *search_efivar = NULL;	unsigned long strsize1, strsize2;	struct list_head *pos, *n;	efi_status_t status = EFI_NOT_FOUND;	int found = 0;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	spin_lock(&efivars_lock);	/*	 * Does this variable already exist?	 */	list_for_each_safe(pos, n, &efivar_list) {		search_efivar = get_efivar_entry(pos);		strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);		strsize2 = utf8_strsize(del_var->VariableName, 1024);		if (strsize1 == strsize2 &&			!memcmp(&(search_efivar->var.VariableName),				del_var->VariableName, strsize1) &&			!efi_guidcmp(search_efivar->var.VendorGuid,				del_var->VendorGuid)) {			found = 1;			break;		}	}	if (!found) {		spin_unlock(&efivars_lock);		return -EINVAL;	}	/* force the Attributes/DataSize to 0 to ensure deletion */	del_var->Attributes = 0;	del_var->DataSize = 0;	status = efi.set_variable(del_var->VariableName,			&del_var->VendorGuid,			del_var->Attributes,			del_var->DataSize,			del_var->Data);	if (status != EFI_SUCCESS) {		printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n",			status);		spin_unlock(&efivars_lock);		return -EIO;	}	/* We need to release this lock before unregistering. */	spin_unlock(&efivars_lock);	efivar_unregister(search_efivar);	/* It's dead Jim.... */	return count;}static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create);static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete);static struct subsys_attribute *var_subsys_attrs[] = {	&var_subsys_attr_new_var,	&var_subsys_attr_del_var,	NULL,};/* * Let's not leave out systab information that snuck into * the efivars driver */static ssize_tsystab_read(struct subsystem *entry, char *buf){	char *str = buf;	if (!entry || !buf)		return -EINVAL;	if (efi.mps)		str += sprintf(str, "MPS=0x%lx\n", __pa(efi.mps));	if (efi.acpi20)		str += sprintf(str, "ACPI20=0x%lx\n", __pa(efi.acpi20));	if (efi.acpi)		str += sprintf(str, "ACPI=0x%lx\n", __pa(efi.acpi));	if (efi.smbios)		str += sprintf(str, "SMBIOS=0x%lx\n", __pa(efi.smbios));	if (efi.hcdp)		str += sprintf(str, "HCDP=0x%lx\n", __pa(efi.hcdp));	if (efi.boot_info)		str += sprintf(str, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));	if (efi.uga)		str += sprintf(str, "UGA=0x%lx\n", __pa(efi.uga));	return str - buf;}static EFI_ATTR(systab, 0400, systab_read, NULL);static struct subsys_attribute *efi_subsys_attrs[] = {	&efi_attr_systab,	NULL,	/* maybe more in the future? */};static decl_subsys(vars, &ktype_efivar, NULL);static decl_subsys(efi, NULL, NULL);/* * efivar_create_sysfs_entry() * Requires: *    variable_name_size = number of bytes required to hold *                         variable_name (not counting the NULL *                         character at the end. *    efivars_lock is not held on entry or exit. * Returns 1 on failure, 0 on success */static intefivar_create_sysfs_entry(unsigned long variable_name_size,			efi_char16_t *variable_name,			efi_guid_t *vendor_guid){	int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;	char *short_name;	struct efivar_entry *new_efivar;	short_name = kmalloc(short_name_size + 1, GFP_KERNEL);	new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL);	if (!short_name || !new_efivar)  {		if (short_name)        kfree(short_name);		if (new_efivar)        kfree(new_efivar);		return 1;	}	memset(short_name, 0, short_name_size+1);	memset(new_efivar, 0, sizeof(struct efivar_entry));	memcpy(new_efivar->var.VariableName, variable_name,		variable_name_size);	memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));	/* Convert Unicode to normal chars (assume top bits are 0),	   ala UTF-8 */	for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) {		short_name[i] = variable_name[i] & 0xFF;	}	/* This is ugly, but necessary to separate one vendor's	   private variables from another's.         */	*(short_name + strlen(short_name)) = '-';	efi_guid_unparse(vendor_guid, short_name + strlen(short_name));	kobject_set_name(&new_efivar->kobj, short_name);	kobj_set_kset_s(new_efivar, vars_subsys);	kobject_register(&new_efivar->kobj);	kfree(short_name); short_name = NULL;	spin_lock(&efivars_lock);	list_add(&new_efivar->list, &efivar_list);	spin_unlock(&efivars_lock);	return 0;}/* * For now we register the efi subsystem with the firmware subsystem * and the vars subsystem with the efi subsystem.  In the future, it * might make sense to split off the efi subsystem into its own * driver, but for now only efivars will register with it, so just * include it here. */static int __initefivars_init(void){	efi_status_t status = EFI_NOT_FOUND;	efi_guid_t vendor_guid;	efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);	struct subsys_attribute *attr;	unsigned long variable_name_size = 1024;	int i, rc = 0, error = 0;	if (!efi_enabled)		return -ENODEV;	printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,	       EFIVARS_DATE);	/*	 * For now we'll register the efi subsys within this driver	 */	rc = firmware_register(&efi_subsys);	if (rc)		return rc;	kset_set_kset_s(&vars_subsys, efi_subsys);	subsystem_register(&vars_subsys);	/*	 * Per EFI spec, the maximum storage allocated for both	 * the variable name and variable data is 1024 bytes.	 */	memset(variable_name, 0, 1024);	do {		variable_name_size = 1024;		status = efi.get_next_variable(&variable_name_size,						variable_name,						&vendor_guid);		switch (status) {		case EFI_SUCCESS:			efivar_create_sysfs_entry(variable_name_size,							variable_name,							&vendor_guid);			break;		case EFI_NOT_FOUND:			break;		default:			printk(KERN_WARNING "efivars: get_next_variable: status=%lx\n",				status);			status = EFI_NOT_FOUND;			break;		}	} while (status != EFI_NOT_FOUND);	/*	 * Now add attributes to allow creation of new vars	 * and deletion of existing ones...	 */	for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) {		if (attr->show && attr->store)			error = subsys_create_file(&vars_subsys, attr);	}	/* Don't forget the systab entry */	for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) {		if (attr->show)			error = subsys_create_file(&efi_subsys, attr);	}	kfree(variable_name);	return 0;}static void __exitefivars_exit(void){	struct list_head *pos, *n;	list_for_each_safe(pos, n, &efivar_list)		efivar_unregister(get_efivar_entry(pos));	subsystem_unregister(&vars_subsys);	firmware_unregister(&efi_subsys);}module_init(efivars_init);module_exit(efivars_exit);

⌨️ 快捷键说明

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