linux-old/arch/ia64/kernel/efivars.c
<<
>>
Prefs
   1/*
   2 * EFI Variables - efivars.c
   3 *
   4 * Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
   5 *
   6 * This code takes all variables accessible from EFI runtime and
   7 *  exports them via /proc
   8 *
   9 * Reads to /proc/efi/vars/varname return an efi_variable_t structure.
  10 * Writes to /proc/efi/vars/varname must be an efi_variable_t structure.
  11 * Writes with DataSize = 0 or Attributes = 0 deletes the variable.
  12 * Writes with a new value in VariableName+VendorGuid creates
  13 * a new variable.
  14 *
  15 *
  16 *  This program is free software; you can redistribute it and/or modify
  17 *  it under the terms of the GNU General Public License as published by
  18 *  the Free Software Foundation; either version 2 of the License, or
  19 *  (at your option) any later version.
  20 *
  21 *  This program is distributed in the hope that it will be useful,
  22 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  23 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24 *  GNU General Public License for more details.
  25 *
  26 *  You should have received a copy of the GNU General Public License
  27 *  along with this program; if not, write to the Free Software
  28 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  29 *
  30 * Changelog:
  31 *
  32 *  10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
  33 *   fix locking per Peter Chubb's findings
  34 * 
  35 *  25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
  36 *   move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
  37 *
  38 *  12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
  39 *   use list_for_each_safe when deleting vars.
  40 *   remove ifdef CONFIG_SMP around include <linux/smp.h>
  41 *   v0.04 release to linux-ia64@linuxia64.org
  42 *
  43 *  20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
  44 *   Moved vars from /proc/efi to /proc/efi/vars, and made
  45 *   efi.c own the /proc/efi directory.
  46 *   v0.03 release to linux-ia64@linuxia64.org
  47 *
  48 *  26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
  49 *   At the request of Stephane, moved ownership of /proc/efi
  50 *   to efi.c, and now efivars lives under /proc/efi/vars.
  51 *
  52 *  12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
  53 *   Feedback received from Stephane Eranian incorporated.
  54 *   efivar_write() checks copy_from_user() return value.
  55 *   efivar_read/write() returns proper errno.
  56 *   v0.02 release to linux-ia64@linuxia64.org
  57 *
  58 *  26 February 2001 - Matt Domsch <Matt_Domsch@dell.com>
  59 *   v0.01 release to linux-ia64@linuxia64.org
  60 */
  61
  62#include <linux/config.h>
  63#include <linux/types.h>
  64#include <linux/errno.h>
  65#include <linux/init.h>
  66#include <linux/proc_fs.h>
  67#include <linux/sched.h>                /* for capable() */
  68#include <linux/mm.h>
  69#include <linux/module.h>
  70#include <linux/smp.h>
  71#include <linux/efi.h>
  72
  73#include <asm/uaccess.h>
  74
  75MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
  76MODULE_DESCRIPTION("/proc interface to EFI Variables");
  77MODULE_LICENSE("GPL");
  78
  79#define EFIVARS_VERSION "0.06 2002-Dec-10"
  80
  81static int
  82efivar_read(char *page, char **start, off_t off,
  83            int count, int *eof, void *data);
  84static int
  85efivar_write(struct file *file, const char *buffer,
  86             unsigned long count, void *data);
  87
  88
  89/*
  90 * The maximum size of VariableName + Data = 1024
  91 * Therefore, it's reasonable to save that much
  92 * space in each part of the structure,
  93 * and we use a page for reading/writing.
  94 */
  95
  96typedef struct _efi_variable_t {
  97        efi_char16_t  VariableName[1024/sizeof(efi_char16_t)];
  98        efi_guid_t    VendorGuid;
  99        unsigned long DataSize;
 100        __u8          Data[1024];
 101        efi_status_t  Status;
 102        __u32         Attributes;
 103} __attribute__((packed)) efi_variable_t;
 104
 105
 106typedef struct _efivar_entry_t {
 107        efi_variable_t          var;
 108        struct proc_dir_entry   *entry;
 109        struct list_head        list;
 110} efivar_entry_t;
 111
 112/*
 113  efivars_lock protects two things:
 114  1) efivar_list - adds, removals, reads, writes
 115  2) efi.[gs]et_variable() calls.
 116  It must not be held when creating proc entries or calling kmalloc.
 117  efi.get_next_variable() is only called from efivars_init(),
 118  which is protected by the BKL, so that path is safe.
 119*/
 120static spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
 121static LIST_HEAD(efivar_list);
 122static struct proc_dir_entry *efi_vars_dir;
 123
 124#define efivar_entry(n) list_entry(n, efivar_entry_t, list)
 125
 126/* Return the number of unicode characters in data */
 127static unsigned long
 128utf8_strlen(efi_char16_t *data, unsigned long maxlength)
 129{
 130        unsigned long length = 0;
 131        while (*data++ != 0 && length < maxlength)
 132                length++;
 133        return length;
 134}
 135
 136/* Return the number of bytes is the length of this string */
 137/* Note: this is NOT the same as the number of unicode characters */
 138static inline unsigned long
 139utf8_strsize(efi_char16_t *data, unsigned long maxlength)
 140{
 141        return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
 142}
 143
 144
 145static int
 146proc_calc_metrics(char *page, char **start, off_t off,
 147                  int count, int *eof, int len)
 148{
 149        if (len <= off+count) *eof = 1;
 150        *start = page + off;
 151        len -= off;
 152        if (len>count) len = count;
 153        if (len<0) len = 0;
 154        return len;
 155}
 156
 157/*
 158 * efivar_create_proc_entry()
 159 * Requires:
 160 *    variable_name_size = number of bytes required to hold
 161 *                         variable_name (not counting the NULL
 162 *                         character at the end.
 163 *    efivars_lock is not held on entry or exit.
 164 * Returns 1 on failure, 0 on success
 165 */
 166static int
 167efivar_create_proc_entry(unsigned long variable_name_size,
 168                         efi_char16_t *variable_name,
 169                         efi_guid_t *vendor_guid)
 170{
 171        int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
 172        char *short_name;
 173        efivar_entry_t *new_efivar;
 174
 175        short_name = kmalloc(short_name_size+1, GFP_KERNEL);
 176        new_efivar = kmalloc(sizeof(efivar_entry_t), GFP_KERNEL);
 177
 178        if (!short_name || !new_efivar)  {
 179                if (short_name)        kfree(short_name);
 180                if (new_efivar)        kfree(new_efivar);
 181                return 1;
 182        }
 183        memset(short_name, 0, short_name_size+1);
 184        memset(new_efivar, 0, sizeof(efivar_entry_t));
 185
 186        memcpy(new_efivar->var.VariableName, variable_name,
 187               variable_name_size);
 188        memcpy(&(new_efivar->var.VendorGuid), vendor_guid, sizeof(efi_guid_t));
 189
 190        /* Convert Unicode to normal chars (assume top bits are 0),
 191           ala UTF-8 */
 192        for (i=0; i< (int) (variable_name_size / sizeof(efi_char16_t)); i++) {
 193                short_name[i] = variable_name[i] & 0xFF;
 194        }
 195
 196        /* This is ugly, but necessary to separate one vendor's
 197           private variables from another's.         */
 198
 199        *(short_name + strlen(short_name)) = '-';
 200        efi_guid_unparse(vendor_guid, short_name + strlen(short_name));
 201
 202        /* Create the entry in proc */
 203        new_efivar->entry = create_proc_entry(short_name, 0600, efi_vars_dir);
 204        kfree(short_name); short_name = NULL;
 205        if (!new_efivar->entry) return 1;
 206
 207        new_efivar->entry->data = new_efivar;
 208        new_efivar->entry->read_proc = efivar_read;
 209        new_efivar->entry->write_proc = efivar_write;
 210
 211        spin_lock(&efivars_lock);
 212        list_add(&new_efivar->list, &efivar_list);
 213        spin_unlock(&efivars_lock);
 214
 215        return 0;
 216}
 217
 218
 219
 220/***********************************************************
 221 * efivar_read()
 222 * Requires:
 223 * Modifies: page
 224 * Returns: number of bytes written, or -EINVAL on failure
 225 ***********************************************************/
 226
 227static int
 228efivar_read(char *page, char **start, off_t off, int count, int *eof, void *data)
 229{
 230        int len = sizeof(efi_variable_t);
 231        efivar_entry_t *efi_var = data;
 232        efi_variable_t *var_data = (efi_variable_t *)page;
 233
 234        if (!page || !data) return -EINVAL;
 235
 236        spin_lock(&efivars_lock);
 237        MOD_INC_USE_COUNT;
 238
 239        memcpy(var_data, &efi_var->var, len);
 240
 241        var_data->DataSize = 1024;
 242        var_data->Status = efi.get_variable(var_data->VariableName,
 243                                            &var_data->VendorGuid,
 244                                            &var_data->Attributes,
 245                                            &var_data->DataSize,
 246                                            var_data->Data);
 247
 248        MOD_DEC_USE_COUNT;
 249        spin_unlock(&efivars_lock);
 250
 251        return proc_calc_metrics(page, start, off, count, eof, len);
 252}
 253
 254/***********************************************************
 255 * efivar_write()
 256 * Requires: data is an efi_setvariable_t data type,
 257 *           properly filled in, possibly by a call
 258 *           first to efivar_read().
 259 *           Caller must have CAP_SYS_ADMIN
 260 * Modifies: NVRAM
 261 * Returns: var_data->DataSize on success, errno on failure
 262 *
 263 ***********************************************************/
 264static int
 265efivar_write(struct file *file, const char *buffer,
 266             unsigned long count, void *data)
 267{
 268        unsigned long strsize1, strsize2;
 269        int found=0;
 270        struct list_head *pos, *n;
 271        unsigned long size = sizeof(efi_variable_t);
 272        efi_status_t status;
 273        efivar_entry_t *efivar = data, *search_efivar = NULL;
 274        efi_variable_t *var_data;
 275        if (!data || count != size) {
 276                printk(KERN_WARNING "efivars: improper struct of size 0x%lx passed.\n", count);
 277                return -EINVAL;
 278        }
 279        if (!capable(CAP_SYS_ADMIN))
 280                return -EACCES;
 281
 282        MOD_INC_USE_COUNT;
 283
 284        var_data = kmalloc(size, GFP_KERNEL);
 285        if (!var_data) {
 286                MOD_DEC_USE_COUNT;
 287                return -ENOMEM;
 288        }
 289        if (copy_from_user(var_data, buffer, size)) {
 290                MOD_DEC_USE_COUNT;
 291                kfree(var_data);
 292                return -EFAULT;
 293        }
 294
 295        spin_lock(&efivars_lock);
 296
 297        /* Since the data ptr we've currently got is probably for
 298           a different variable find the right variable.
 299           This allows any properly formatted data structure to
 300           be written to any of the files in /proc/efi/vars and it will work.
 301        */
 302        list_for_each_safe(pos, n, &efivar_list) {
 303                search_efivar = efivar_entry(pos);
 304                strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
 305                strsize2 = utf8_strsize(var_data->VariableName, 1024);
 306                if ( strsize1 == strsize2 &&
 307                     !memcmp(&(search_efivar->var.VariableName),
 308                             var_data->VariableName, strsize1) &&
 309                     !efi_guidcmp(search_efivar->var.VendorGuid,
 310                                  var_data->VendorGuid)) {
 311                        found = 1;
 312                        break;
 313                }
 314        }
 315        if (found) efivar = search_efivar;
 316
 317        status = efi.set_variable(var_data->VariableName,
 318                                  &var_data->VendorGuid,
 319                                  var_data->Attributes,
 320                                  var_data->DataSize,
 321                                  var_data->Data);
 322
 323        if (status != EFI_SUCCESS) {
 324                printk(KERN_WARNING "set_variable() failed: status=%lx\n", status);
 325                kfree(var_data);
 326                MOD_DEC_USE_COUNT;
 327                spin_unlock(&efivars_lock);
 328                return -EIO;
 329        }
 330
 331
 332        if (!var_data->DataSize || !var_data->Attributes) {
 333                /* We just deleted the NVRAM variable */
 334                remove_proc_entry(efivar->entry->name, efi_vars_dir);
 335                list_del(&efivar->list);
 336                kfree(efivar);
 337        }
 338
 339        spin_unlock(&efivars_lock);
 340
 341        /* If this is a new variable, set up the proc entry for it. */
 342        if (!found) {
 343                efivar_create_proc_entry(utf8_strsize(var_data->VariableName,
 344                                                      1024),
 345                                         var_data->VariableName,
 346                                         &var_data->VendorGuid);
 347        }
 348
 349        kfree(var_data);
 350        MOD_DEC_USE_COUNT;
 351        return size;
 352}
 353
 354/*
 355 * The EFI system table contains pointers to the SAL system table,
 356 * HCDP, ACPI, SMBIOS, etc, that may be useful to applications.
 357 */
 358static ssize_t
 359efi_systab_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 360{
 361        void *data;
 362        u8 *proc_buffer;
 363        ssize_t size, length;
 364        int ret;
 365        const int max_nr_entries = 7;   /* num ptrs to tables we could expose */
 366        const int max_line_len = 80;
 367        loff_t pos = *ppos;
 368
 369        if (!efi.systab)
 370                return 0;
 371
 372        proc_buffer = kmalloc(max_nr_entries * max_line_len, GFP_KERNEL);
 373        if (!proc_buffer)
 374                return -ENOMEM;
 375
 376        length = 0;
 377        if (efi.mps)
 378                length += sprintf(proc_buffer + length, "MPS=0x%lx\n", __pa(efi.mps));
 379        if (efi.acpi20)
 380                length += sprintf(proc_buffer + length, "ACPI20=0x%lx\n", __pa(efi.acpi20));
 381        if (efi.acpi)
 382                length += sprintf(proc_buffer + length, "ACPI=0x%lx\n", __pa(efi.acpi));
 383        if (efi.smbios)
 384                length += sprintf(proc_buffer + length, "SMBIOS=0x%lx\n", __pa(efi.smbios));
 385        if (efi.sal_systab)
 386                length += sprintf(proc_buffer + length, "SAL=0x%lx\n", __pa(efi.sal_systab));
 387        if (efi.hcdp)
 388                length += sprintf(proc_buffer + length, "HCDP=0x%lx\n", __pa(efi.hcdp));
 389        if (efi.boot_info)
 390                length += sprintf(proc_buffer + length, "BOOTINFO=0x%lx\n", __pa(efi.boot_info));
 391
 392        if (pos != (unsigned) pos || pos >= length) {
 393                ret = 0;
 394                goto out;
 395        }
 396
 397        data = proc_buffer + pos;
 398        size = length - pos;
 399        if (size > count)
 400                size = count;
 401        if (copy_to_user(buffer, data, size)) {
 402                ret = -EFAULT;
 403                goto out;
 404        }
 405
 406        *ppos = pos + size;
 407        ret = size;
 408
 409out:
 410        kfree(proc_buffer);
 411        return ret;
 412}
 413
 414static struct proc_dir_entry *efi_systab_entry;
 415static struct file_operations efi_systab_fops = {
 416        .read = efi_systab_read,
 417};
 418
 419static int __init
 420efivars_init(void)
 421{
 422        efi_status_t status;
 423        efi_guid_t vendor_guid;
 424        efi_char16_t *variable_name = kmalloc(1024, GFP_KERNEL);
 425        unsigned long variable_name_size = 1024;
 426
 427        printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
 428
 429        /* Since efi.c happens before procfs is available,
 430           we create the directory here if it doesn't
 431           already exist.  There's probably a better way
 432           to do this.
 433        */
 434        if (!efi_dir)
 435                efi_dir = proc_mkdir("efi", NULL);
 436
 437        efi_systab_entry = create_proc_entry("systab", S_IRUSR | S_IRGRP, efi_dir);
 438        if (efi_systab_entry)
 439                efi_systab_entry->proc_fops = &efi_systab_fops;
 440
 441        efi_vars_dir = proc_mkdir("vars", efi_dir);
 442
 443        /* Per EFI spec, the maximum storage allocated for both
 444           the variable name and variable data is 1024 bytes.
 445        */
 446
 447        memset(variable_name, 0, 1024);
 448
 449        do {
 450                variable_name_size=1024;
 451
 452                status = efi.get_next_variable(&variable_name_size,
 453                                               variable_name,
 454                                               &vendor_guid);
 455
 456
 457                switch (status) {
 458                case EFI_SUCCESS:
 459                        efivar_create_proc_entry(variable_name_size,
 460                                                 variable_name,
 461                                                 &vendor_guid);
 462                        break;
 463                case EFI_NOT_FOUND:
 464                        break;
 465                default:
 466                        printk(KERN_WARNING "get_next_variable: status=%lx\n", status);
 467                        status = EFI_NOT_FOUND;
 468                        break;
 469                }
 470
 471        } while (status != EFI_NOT_FOUND);
 472
 473        kfree(variable_name);
 474        return 0;
 475}
 476
 477static void __exit
 478efivars_exit(void)
 479{
 480        struct list_head *pos, *n;
 481        efivar_entry_t *efivar;
 482
 483        spin_lock(&efivars_lock);
 484        if (efi_systab_entry)
 485                remove_proc_entry(efi_systab_entry->name, efi_dir);
 486        list_for_each_safe(pos, n, &efivar_list) {
 487                efivar = efivar_entry(pos);
 488                remove_proc_entry(efivar->entry->name, efi_vars_dir);
 489                list_del(&efivar->list);
 490                kfree(efivar);
 491        }
 492        spin_unlock(&efivars_lock);
 493
 494        remove_proc_entry(efi_vars_dir->name, efi_dir);
 495}
 496
 497module_init(efivars_init);
 498module_exit(efivars_exit);
 499
 500/*
 501 * Overrides for Emacs so that we follow Linus's tabbing style.
 502 * Emacs will notice this stuff at the end of the file and automatically
 503 * adjust the settings for this buffer only.  This must remain at the end
 504 * of the file.
 505 * ---------------------------------------------------------------------------
 506 * Local variables:
 507 * c-indent-level: 4
 508 * c-brace-imaginary-offset: 0
 509 * c-brace-offset: -4
 510 * c-argdecl-indent: 4
 511 * c-label-offset: -4
 512 * c-continued-statement-offset: 4
 513 * c-continued-brace-offset: 0
 514 * indent-tabs-mode: nil
 515 * tab-width: 8
 516 * End:
 517 */
 518
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.