Imported Upstream version 0.4.9 upstream/0.4.9
authorBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:06:17 +0000 (23:06 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:06:17 +0000 (23:06 -0600)
16 files changed:
AUTHORS
Makefile
README
doc/ChangeLog
src/efibootmgr/efibootmgr.c
src/efibootmgr/module.mk
src/include/efi.h
src/include/efibootmgr.h
src/include/efivars_procfs.h [new file with mode: 0644]
src/include/efivars_sysfs.h [new file with mode: 0644]
src/lib/efi.c
src/lib/efivars_procfs.c [new file with mode: 0644]
src/lib/efivars_sysfs.c [new file with mode: 0644]
src/lib/gpt.c
src/man/man8/efibootmgr.8
src/man/man8/efibootmgr.8.docbook

diff --git a/AUTHORS b/AUTHORS
index 3059aa5139316f6e9bf0cb8c059548d37cd1d48d..bd8127de5416fe3f412433856f4ab68764627f5a 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,3 +13,6 @@ dann frazier <dannf@debian.org>
 - Patches to efibootmgr.c
 - network boot entry creation in efi.c
 
+Joshua Giles <Joshua_Giles@dell.com>
+- walk the PCI path inserting parent bridge device path components for
+  network boot and EDD30 entries.
index 67d275ac7d4672fde40a9803289ea9c20f7f0051..b7162d83b59122538d9abd93c2c29b362531cf6d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,10 @@
   default: all
 
-  RELEASE_DATE := "04-Sep-2003"
+  RELEASE_DATE := "09-Jun-2004"
   RELEASE_MAJOR := 0
-  RELEASE_MINOR := 4
-  RELEASE_SUBLEVEL := 2
-  RELEASE_EXTRALEVEL :=
+  RELEASE_MINOR := 5
+  RELEASE_SUBLEVEL := 0
+  RELEASE_EXTRALEVEL := -test4
   RELEASE_NAME := efibootmgr
   RELEASE_STRING := $(RELEASE_NAME)-$(RELEASE_MAJOR).$(RELEASE_MINOR).$(RELEASE_SUBLEVEL)$(RELEASE_EXTRALEVEL)
 
diff --git a/README b/README
index 1fb38fdb13281a824aa932ae99d3e62137a3c71c..9ee586be5b94b95e3728f854fd7cef52a026841c 100644 (file)
--- a/README
+++ b/README
@@ -29,7 +29,9 @@ usage: efibootmgr [options]
        -O | --delete-bootorder delete BootOrder
        -p | --part part       (defaults to 1) containing loader
        -q | --quiet           be quiet
-       -t | --test filename   don't write to NVRAM, write to filename
+       --test filename   don't write to NVRAM, write to filename
+       -t | --timeout seconds   Boot manager timeout
+       -T | --delete-timeout    delete Timeout value
        -u | --unicode | --UCS-2  pass extra args as UCS-2 (default is ASCII)
        -U | --acpi_uid XXXX    set the ACPI UID (used with -i)
        -v | --verbose         print additional information
@@ -43,6 +45,7 @@ Typical usage:
   BootCurrent: 0004
   BootNext: 0003
   BootOrder: 0004,0000,0001,0002,0003
+  Timeout: 30 seconds
   Boot0000* Diskette Drive(device:0)
   Boot0001* CD-ROM Drive(device:FF) 
   Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)   
@@ -62,6 +65,10 @@ Typical usage:
   boot manager after first use.  This allows you to change the next boot
   behavior without changing BootOrder.
 
+  Timeout - the time in seconds between when the boot manager appears
+  on the screen until when it automatically chooses the startup value
+  from BootNext or BootOrder.
+
   Five boot entries (0000 - 0004), the active/inactive flag (* means
   active), and the name displayed on the screen.
 
index 5daad8f12f63d86108781e99b2801bdee918b09d..8ba7756904b7f3a1bb6a56bc08491442f402bacd 100644 (file)
@@ -1,3 +1,34 @@
+* Wed Jun 07 2004 Matt Domsch <Matt_Domsch@dell.com>
+- Fixed bug where read_boot_order() would wrongly return EFI_NOT_FOUND
+  when it needed to create a new BootOrder variable.  Reported by Micah Parrish.
+- Added code to recursively walk the PCI bus putting parent PCI bridges
+  in.  This is necessary for Dell PowerEdge 3250 and 7250 servers and
+  Intel Tiger2 and Tiger4 platforms when creating PXE boot entries for
+  the onboard NICs, and if creating EDD30 boot path entries.  Work by Matt
+  and Joshua Giles.
+  - Note, efibootmgr now requires libpci for building.
+- Released v0.5.0-test4
+
+* Sat Apr 24 2004 Matt Domsch <Matt_Domsch@dell.com>
+- Fixed reversed logic of create_or_edit_variable which prevented object
+  creation or editing on sysfs.
+- Removed debug printfs in sysfs read/write commands.
+- Released v0.5.0-test3
+
+* Thu Feb 04 2004 Matt Domsch <Matt_Domsch@dell.com>
+- removed -t short option for --test
+- added -t <timeout> and -T delete timeout options
+- updated man page and README about the timeout options
+- Released v0.5.0-test2
+
+* Tue Sep 09 2003 Matt Domsch <Matt_Domsch@dell.com>
+- Released v0.5.0-test1
+
+* Thu Sep 04 2003 Matt Domsch <Matt_Domsch@dell.com>
+- Seperated access to variables through /proc into efivars_procfs.[ch]
+- Added efivars_sysfs.h to access variables through sysfs.
+- Moved around some functions, cleaned up some duplication.
+
 * Thu Sep 04 2003 Matt Domsch <Matt_Domsch@dell.com>
 - released v0.4.2-test2 as v0.4.2 without additional changes.
 
index 41841432d8cdbe4bcd864d84a4b829fe525f3242..1aa3595e38253686e430c4f6c7ac86df1679b033 100644 (file)
@@ -1,7 +1,7 @@
 /*
   efibootmgr.c - Manipulates EFI variables as exported in /proc/efi/vars
 
-  Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+  Copyright (C) 2001-2004 Dell, Inc. <Matt_Domsch@dell.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -49,6 +49,7 @@
 #include "disk.h"
 #include "efibootmgr.h"
 
+
 #ifndef EFIBOOTMGR_VERSION
 #define EFIBOOTMGR_VERSION "unknown (fix Makefile!)"
 #endif
@@ -73,55 +74,27 @@ var_num_from_name(const char *pattern, char *name, uint16_t *num)
        sscanf(name, pattern, num);
 }
 
-static int
-select_boot_var_names(const struct dirent *d)
+static void
+fill_bootvar_name(char *dest, size_t len, const char *name)
 {
-       int num, rc;
-       rc = sscanf(d->d_name, "Boot0%03x-%*s", &num);
-       return rc;
+       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
+       char text_uuid[40];
+       efi_guid_unparse(&guid, text_uuid);
+       snprintf(dest, len, "%s-%s", name, text_uuid);
 }
 
-#if 0
-static int
-select_blk_var_names(const struct dirent *d)
+static void
+fill_var(efi_variable_t *var, const char *name)
 {
-       int num;
-       return sscanf(d->d_name, "blk%x-%*s", &num);
-}
-#endif
+       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
 
-static int
-read_boot_var_names(struct dirent ***namelist)
-{
-       int n;
-       n = scandir(PROC_DIR_EFI_VARS, namelist, select_boot_var_names, alphasort);
-       if (n < 0) {
-               perror("scandir " PROC_DIR_EFI_VARS);
-               fprintf(stderr, "You must 'modprobe efivars' before running efibootmgr.\n");
-       }
-       return n;
+       efichar_from_char(var->VariableName, name, 1024);
+       memcpy(&var->VendorGuid, &guid, sizeof(guid));
+       var->Attributes = EFI_VARIABLE_NON_VOLATILE
+               | EFI_VARIABLE_BOOTSERVICE_ACCESS
+               | EFI_VARIABLE_RUNTIME_ACCESS;
 }
 
-#if 0
-static int
-read_blk_var_names(struct dirent ***namelist)
-{
-       int n;
-       n = scandir(PROC_DIR_EFI_VARS, namelist, select_blk_var_names, alphasort);
-       if (n < 0)
-               perror("scandir");
-       return n;
-}
-
-static int
-dirent_list_length(struct dirent **namelist)
-{
-       int i;
-       if (!namelist) return 0;
-       for (i=0; namelist[i]; i++);
-       return i;
-}
-#endif
 
 static void
 read_vars(struct dirent **namelist,
@@ -273,42 +246,39 @@ make_boot_var(list_t *boot_list)
                free(boot);
                return NULL;
        }
-       write_variable(&boot->var_data);
+       create_variable(&boot->var_data);
        list_add_tail(&boot->list, boot_list);
        return boot;
 }
 
+
+
+static efi_status_t
+read_boot(efi_variable_t *var, const char *name)
+{
+       char name_guid[PATH_MAX];
+
+       memset(var, 0, sizeof(*var));
+       fill_bootvar_name(name_guid, sizeof(name_guid), name);
+       return read_variable(name_guid, var);
+}
+
 static efi_status_t
 read_boot_order(efi_variable_t *boot_order)
 {
        efi_status_t status;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       char boot_order_name[80], text_uuid[40];
-       efi_guid_unparse(&guid, text_uuid);
-
-       memset(boot_order, 0, sizeof(*boot_order));
-       sprintf(boot_order_name, "BootOrder-%s", text_uuid);
 
-       status = read_variable(boot_order_name, boot_order);
+       status = read_boot(boot_order, "BootOrder");
        if (status != EFI_SUCCESS && status != EFI_NOT_FOUND)
                return status;
 
        if (status == EFI_NOT_FOUND) {
-               /* Create it */
-               efichar_from_char(boot_order->VariableName, "BootOrder",
-                                 1024);
-               memcpy(&boot_order->VendorGuid, &guid, sizeof(guid));
-               boot_order->Attributes = EFI_VARIABLE_NON_VOLATILE 
-                       | EFI_VARIABLE_BOOTSERVICE_ACCESS
-                       | EFI_VARIABLE_RUNTIME_ACCESS;
-               return status;
+               fill_var(boot_order, "BootOrder");
        }
        return EFI_SUCCESS;
 }
 
 
-
-
 static efi_status_t
 add_to_boot_order(uint16_t num)
 {
@@ -333,7 +303,7 @@ add_to_boot_order(uint16_t num)
        /* Now new_data has what we need */
        memcpy(&(boot_order.Data), new_data, new_data_size);
        boot_order.DataSize = new_data_size;
-       return write_variable(&boot_order);
+       return create_or_edit_variable(&boot_order);
 }
 
 
@@ -345,13 +315,16 @@ remove_from_boot_order(uint16_t num)
        uint64_t new_data_size;
        uint16_t *new_data, *old_data;
        int old_i,new_i;
+       char boot_order_name[PATH_MAX];
 
        status = read_boot_order(&boot_order);
        if (status != EFI_SUCCESS) return status;
-
        /* If it's empty, yea! */
        if (!boot_order.DataSize) return EFI_SUCCESS;
 
+       fill_bootvar_name(boot_order_name, sizeof(boot_order_name),
+                         "BootOrder");
+
        /* We've now got an array (in boot_order.Data) of the
           boot order.  Simply copy the array, skipping the
           entry we're deleting.
@@ -376,101 +349,59 @@ remove_from_boot_order(uint16_t num)
        memcpy(&(boot_order.Data), new_data, new_data_size);
        boot_order.DataSize = new_data_size;
 
-       return write_variable(&boot_order);
+       return edit_variable(&boot_order);
 }
 
-static int
-read_boot_current()
+static efi_status_t
+delete_var(const char *name)
 {
-       efi_status_t status;
-       efi_variable_t boot_next;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       char boot_next_name[80], text_uuid[40];
-       uint16_t *n = (uint16_t *)(boot_next.Data);
-
-       efi_guid_unparse(&guid, text_uuid);
-
-       memset(&boot_next, 0, sizeof(boot_next));
-       sprintf(boot_next_name, "BootCurrent-%s", text_uuid);
-
-       status = read_variable(boot_next_name, &boot_next);
-       if (status) return -1;
+       efi_variable_t var;
 
-       return *n;
+       memset(&var, 0, sizeof(var));
+       fill_var(&var, name);
+       return delete_variable(&var);
 }
 
 static int
-read_boot_next()
+read_boot_u16(const char *name)
 {
        efi_status_t status;
-       efi_variable_t boot_next;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       char boot_next_name[80], text_uuid[40];
-       uint16_t *n = (uint16_t *)(boot_next.Data);
-
-       efi_guid_unparse(&guid, text_uuid);
-
-       memset(&boot_next, 0, sizeof(boot_next));
-       sprintf(boot_next_name, "BootNext-%s", text_uuid);
+       efi_variable_t var;
+       uint16_t *n = (uint16_t *)(var.Data);
 
-       status = read_variable(boot_next_name, &boot_next);
+       memset(&var, 0, sizeof(var));
+       status = read_boot(&var, name);
        if (status) return -1;
-
        return *n;
 }
 
-
 static efi_status_t
-set_boot_next(uint16_t num)
+set_boot_u16(const char *name, uint16_t num)
 {
        efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
        uint16_t *n = (uint16_t *)var.Data;
 
        memset(&var, 0, sizeof(var));
 
-       efichar_from_char(var.VariableName, "BootNext",
-                         1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
+       fill_var(&var, name);
        *n = num;
        var.DataSize = sizeof(uint16_t);
-       var.Attributes = EFI_VARIABLE_NON_VOLATILE 
-               | EFI_VARIABLE_BOOTSERVICE_ACCESS
-               | EFI_VARIABLE_RUNTIME_ACCESS;
-       return write_variable(&var);
+       return create_or_edit_variable(&var);
 }
 
-static efi_status_t
-delete_boot_next()
-{
-       efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-
-       memset(&var, 0, sizeof(var));
-
-       efichar_from_char(var.VariableName, "BootNext",
-                         1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
-       return write_variable(&var);
-}
-
-
 static efi_status_t
 delete_boot_var(uint16_t num)
 {
        efi_status_t status;
        efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       char name[80];
+       char name[16];
        list_t *pos, *n;
        var_entry_t *boot;
-       sprintf(name, "Boot%04x", num);
 
+       snprintf(name, sizeof(name), "Boot%04x", num);
        memset(&var, 0, sizeof(var));
-
-       efichar_from_char(var.VariableName, name, 1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
-       status = write_variable(&var);
+       fill_var(&var, name);
+       status = delete_variable(&var);
 
        if (status) return status;
 
@@ -624,23 +555,16 @@ parse_boot_order(char *buffer, uint16_t *order, int length)
 static efi_status_t
 set_boot_order()
 {
-       efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-       uint16_t *n = (uint16_t *)var.Data;
+       efi_variable_t boot_order;
+       uint16_t *n = (uint16_t *)boot_order.Data;
 
        if (!opts.bootorder) return EFI_SUCCESS;
 
-       memset(&var, 0, sizeof(var));
+       memset(&boot_order, 0, sizeof(boot_order));
+       fill_var(&boot_order, "BootOrder");
 
-       efichar_from_char(var.VariableName, "BootOrder",
-                         1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
-       var.Attributes = EFI_VARIABLE_NON_VOLATILE
-               | EFI_VARIABLE_BOOTSERVICE_ACCESS
-               | EFI_VARIABLE_RUNTIME_ACCESS;
-
-       var.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
-       return write_variable(&var);
+       boot_order.DataSize = parse_boot_order(opts.bootorder, n, 1024/sizeof(uint16_t)) * sizeof(uint16_t);
+       return create_or_edit_variable(&boot_order);
 }
 
 static void
@@ -733,7 +657,7 @@ set_active_state()
                                else {
                                        load_option->attributes
                                                |= LOAD_OPTION_ACTIVE;
-                                       return write_variable(&boot->var_data);
+                                       return edit_variable(&boot->var_data);
                                }
                        }
                        else if (opts.active == 0) {
@@ -743,7 +667,7 @@ set_active_state()
                                else {
                                        load_option->attributes
                                                &= ~LOAD_OPTION_ACTIVE;
-                                       return write_variable(&boot->var_data);
+                                       return edit_variable(&boot->var_data);
                                }
                        }
                }
@@ -753,20 +677,6 @@ set_active_state()
 
 
 
-static efi_status_t
-delete_boot_order()
-{
-       efi_variable_t var;
-       efi_guid_t guid = EFI_GLOBAL_VARIABLE;
-
-       memset(&var, 0, sizeof(var));
-
-       efichar_from_char(var.VariableName, "BootOrder",
-                         1024);
-       memcpy(&var.VendorGuid, &guid, sizeof(guid));
-       return write_variable(&var);
-}
-
 
 static void
 usage()
@@ -792,7 +702,9 @@ usage()
        printf("\t-O | --delete-bootorder delete BootOrder\n");
        printf("\t-p | --part part        (defaults to 1) containing loader\n");
        printf("\t-q | --quiet            be quiet\n");
-       printf("\t-t | --test filename    don't write to NVRAM, write to filename.\n");
+       printf("\t   | --test filename    don't write to NVRAM, write to filename.\n");
+       printf("\t-t | --timeout seconds  set boot manager timeout waiting for user input.\n");
+       printf("\t-T | --delete-timeout   delete Timeout.\n");
        printf("\t-u | --unicode | --UCS-2  pass extra args as UCS-2 (default is ASCII)\n");
        printf("\t-U | --acpi_uid XXXX    set the ACPI UID (used with -i)\n");
        printf("\t-v | --verbose          print additional information\n");
@@ -807,6 +719,7 @@ set_default_opts()
        opts.bootnum         = -1;   /* auto-detect */
        opts.bootnext        = -1;   /* Don't set it */
        opts.active          = -1;   /* Don't set it */
+       opts.timeout         = -1;   /* Don't set it */
        opts.edd10_devicenum = 0x80;
        opts.loader          = "\\elilo.efi";
        opts.label           = "Linux";
@@ -835,7 +748,7 @@ parse_opts(int argc, char **argv)
                        {"create",                 no_argument, 0, 'c'},
                        {"disk",             required_argument, 0, 'd'},
                        {"iface",            required_argument, 0, 'i'},
-                       {"acpi_hid",         required_argument, 0, 'H' },
+                       {"acpi_hid",         required_argument, 0, 'H'},
                        {"edd-device",       required_argument, 0, 'E'},
                        {"edd30",            required_argument, 0, 'e'},
                        {"gpt",                    no_argument, 0, 'g'},
@@ -847,10 +760,12 @@ parse_opts(int argc, char **argv)
                        {"delete-bootorder",       no_argument, 0, 'O'},
                        {"part",             required_argument, 0, 'p'},
                        {"quiet",                  no_argument, 0, 'q'},
-                       {"test",             required_argument, 0, 't'},
+                       {"test",             required_argument, 0,   1},
+                       {"timeout",          required_argument, 0, 't'},
+                       {"delete-timeout",         no_argument, 0, 'T'},
                        {"unicode",                no_argument, 0, 'u'},
                        {"UCS-2",                  no_argument, 0, 'u'},
-                       {"acpi_uid",         required_argument, 0, 'U' },
+                       {"acpi_uid",         required_argument, 0, 'U'},
                        {"verbose",          optional_argument, 0, 'v'},
                        {"version",                no_argument, 0, 'V'},
                        {"write-signature",        no_argument, 0, 'w'},
@@ -858,7 +773,7 @@ parse_opts(int argc, char **argv)
                };
 
                c = getopt_long (argc, argv,
-                                "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:uU:v::Vw",
+                                "AaBb:cd:e:E:gH:i:l:L:n:No:Op:qt:TuU:v::Vw",
                                 long_options, &option_index);
                if (c == -1)
                        break;
@@ -928,9 +843,19 @@ parse_opts(int argc, char **argv)
                case 'q':
                        opts.quiet = 1;
                        break;
-               case 't':
+               case 1:
                        opts.testfile = optarg;
                        break;
+               case 't':
+                       rc = sscanf(optarg, "%u", &num);
+                       if (rc == 1) {
+                               opts.timeout = num;
+                               opts.set_timeout = 1;
+                       }
+                       break;
+               case 'T':
+                       opts.delete_timeout = 1;
+                       break;
                case 'u':
                        opts.unicode = 1;
                        break;
@@ -989,6 +914,9 @@ main(int argc, char **argv)
                return 1;
        }
 
+       if (!opts.testfile)
+               set_fs_kernel_calls();
+
        if (!opts.testfile) {
                num_boot_names = read_boot_var_names(&boot_names);
                read_vars(boot_names, num_boot_names, &boot_entry_list);
@@ -1017,7 +945,7 @@ main(int argc, char **argv)
        if (!opts.testfile) {
 
                if (opts.delete_bootorder) {
-                       delete_boot_order();
+                       delete_var("BootOrder");
                }
 
                if (opts.bootorder) {
@@ -1026,22 +954,34 @@ main(int argc, char **argv)
 
 
                if (opts.delete_bootnext) {
-                       delete_boot_next();
+                       delete_var("BootNext");
+               }
+
+               if (opts.delete_timeout) {
+                       delete_var("Timeout");
                }
 
                if (opts.bootnext >= 0) {
-                       set_boot_next(opts.bootnext & 0xFFFF);
+                       set_boot_u16("BootNext", opts.bootnext & 0xFFFF);
+               }
+
+               if (opts.set_timeout) {
+                       set_boot_u16("Timeout", opts.timeout);
                }
 
                if (!opts.quiet) {
-                       num = read_boot_next();
+                       num = read_boot_u16("BootNext");
                        if (num != -1 ) {
                                printf("BootNext: %04x\n", num);
                        }
-                       num = read_boot_current();
+                       num = read_boot_u16("BootCurrent");
                        if (num != -1) {
                                printf("BootCurrent: %04x\n", num);
                        }
+                       num = read_boot_u16("Timeout");
+                       if (num != -1) {
+                               printf("Timeout: %u seconds\n", num);
+                       }
                        show_boot_order();
                        show_boot_vars();
                }
index 7764641743e4a318a3a395f0e214cdd94e06dece..dac4907e8b486a718e2da313abcceb048f8ddb72 100644 (file)
@@ -2,21 +2,23 @@ efibootmgr_SRCDIR := src/efibootmgr
 efibootmgr_OBJECTS := efibootmgr.o
 efibootmgr_TARGETS := efibootmgr
 efibootmgr_FULLTARGET :=  \
-       $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_TARGETS))
+       $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_TARGETS))
 efibootmgr_FULLOBJECT :=  \
-       $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_OBJECT))
+       $(patsubst %, $(efibootmgr_SRCDIR)/%, $(efibootmgr_OBJECT))
 
 efibootmgr_LIBS    := crc32.o disk.o efi.o efichar.o gpt.o scsi_ioctls.o \
-                      unparse_path.o
+                      unparse_path.o efivars_procfs.o efivars_sysfs.o
 efibootmgr_LIBDIR  := src/lib
 efibootmgr_FULLLIB := \
-       $(patsubst %,$(efibootmgr_LIBDIR)/%,$(efibootmgr_LIBS))
+       $(patsubst %,$(efibootmgr_LIBDIR)/%,$(efibootmgr_LIBS))
+LIBS = -lpci
 
-ALLDEPS += $(efibootmgr_FULLTARGET) 
+ALLDEPS += $(efibootmgr_FULLTARGET)
 CLEANLIST += $(efibootmgr_FULLTARGET)
 CLEANLIST += $(efibootmgr_FULLOBJECT)
-bindir_TARGETS += $(efibootmgr_FULLTARGET) 
+bindir_TARGETS += $(efibootmgr_FULLTARGET)
 
 $(efibootmgr_FULLTARGET): \
-       $(efibootmgr_FULLOBJECT) \
-       $(efibootmgr_FULLLIB)
+       $(efibootmgr_FULLOBJECT) \
+       $(efibootmgr_FULLLIB) \
+       $(LIBS)
index b53187edb80c824685c72243843e1203466ea203..5fc52ff48fdc678f34ad95503b725436c9ab3ec9 100644 (file)
@@ -1,8 +1,8 @@
 /*
-  efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
-  Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
+  efi.[ch] - Extensible Firmware Interface definitions
+
+  Copyright (C) 2001, 2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -27,6 +27,7 @@
  *      version 1.02, 12 December, 2000
  */
 #include <stdint.h>
+#include <dirent.h>
 
 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
 
@@ -336,24 +337,34 @@ typedef struct {
 } __attribute__((packed)) END_DEVICE_PATH;
 
 
-/* Used for ACPI _HID */
-#define EISAID_PNP0A03 0xa0341d0
-
-#define PROC_DIR_EFI_VARS "/proc/efi/vars/"
+struct efivar_kernel_calls {
+        efi_status_t (*read)(const char *name, efi_variable_t *var);
+        efi_status_t (*edit)(const char *name, efi_variable_t *var);
+        efi_status_t (*create)(efi_variable_t *var);
+        efi_status_t (*delete)(efi_variable_t *var);
+        char *path;
+};
 
 
+/* Used for ACPI _HID */
+#define EISAID_PNP0A03 0xa0341d0
 
 /* Exported functions */
 
-efi_status_t read_variable(char *name, efi_variable_t *var);
-efi_status_t write_variable(efi_variable_t *var);
-int make_linux_efi_variable(efi_variable_t *var,
+extern int make_linux_efi_variable(efi_variable_t *var,
                            unsigned int free_number);
-char * efi_guid_unparse(efi_guid_t *guid, char *out);
-EFI_DEVICE_PATH *load_option_path(EFI_LOAD_OPTION *option);
-
-
+extern char * efi_guid_unparse(efi_guid_t *guid, char *out);
+extern EFI_DEVICE_PATH *load_option_path(EFI_LOAD_OPTION *option);
 
+extern efi_status_t read_variable(const char *name, efi_variable_t *var);
+extern efi_status_t edit_variable(efi_variable_t *var);
+extern efi_status_t create_variable(efi_variable_t *var);
+extern efi_status_t delete_variable(efi_variable_t *var);
+extern efi_status_t create_or_edit_variable(efi_variable_t *var);
 
+extern void set_fs_kernel_calls();
+extern int read_boot_var_names(struct dirent ***namelist);
+extern int variable_to_name(efi_variable_t *var, char *name);
+extern int var_name_to_path(const char *name, char *path);
 
-#endif /* _ASM_IA64_EFI_H */
+#endif /* EFI_H */
index 163793f61cff0da07da05a6be5d3077922ca15a8..3546834d5b5f2eff17bb679840ea78af0229f3e4 100644 (file)
@@ -49,6 +49,9 @@ typedef struct {
        unsigned int unicode:1;
        unsigned int write_signature:1;
        unsigned int forcegpt:1;
+       unsigned int set_timeout:1;
+       unsigned int delete_timeout:1;
+       unsigned short int timeout;
 } efibootmgr_opt_t;
 
 
diff --git a/src/include/efivars_procfs.h b/src/include/efivars_procfs.h
new file mode 100644 (file)
index 0000000..2f0958d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+  efivars_procfs.h - EFI Variables accessed through /proc/efi/vars
+
+  Copyright (C) 2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef EFIVARS_PROCFS_H
+#define EFIVARS_PROCFS_H
+
+#include "efi.h"
+
+#define PROCFS_DIR_EFI_VARS "/proc/efi/vars"
+
+extern struct efivar_kernel_calls procfs_kernel_calls;
+
+#endif /* EFIVARS_PROCFS_H */
diff --git a/src/include/efivars_sysfs.h b/src/include/efivars_sysfs.h
new file mode 100644 (file)
index 0000000..1e24810
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+  efivars_sysfs.h - EFI Variables accessed through /sys/firmware/efi/vars
+
+  Copyright (C) 2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef EFIVARS_SYSFS_H
+#define EFIVARS_SYSFS_H
+
+#include "efi.h"
+
+#define SYSFS_DIR_EFI_VARS "/sys/firmware/efi/vars"
+
+extern struct efivar_kernel_calls sysfs_kernel_calls;
+
+#endif /* EFIVARS_SYSFS_H */
index 0ab0339b23a852d591dfa38236b4394f99a5da88..1f0f3dbc94fdf61d4a3a364360600ebef7847eba 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  efi.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
+  efivars_proc.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
 
   Copyright (C) 2001,2003 Dell Computer Corporation <Matt_Domsch@dell.com>
 
 #include <sys/ioctl.h>
 #include <linux/sockios.h>
 #include <net/if.h>
-
-typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */
-typedef __uint32_t u32;         /* ditto */
-typedef __uint16_t u16;         /* ditto */
-typedef __uint8_t u8;           /* ditto */
-
+#include <pci/pci.h>
 #include <linux/ethtool.h>
 #include "efi.h"
 #include "efichar.h"
 #include "scsi_ioctls.h"
 #include "disk.h"
 #include "efibootmgr.h"
+#include "efivars_procfs.h"
+#include "efivars_sysfs.h"
+#include "list.h"
+
+static struct efivar_kernel_calls *fs_kernel_calls;
 
 EFI_DEVICE_PATH *
 load_option_path(EFI_LOAD_OPTION *option)
@@ -69,36 +69,33 @@ efi_guid_unparse(efi_guid_t *guid, char *out)
         return out;
 }
 
-
-efi_status_t
-read_variable(char *name, efi_variable_t *var)
+void
+set_fs_kernel_calls()
 {
-       int newnamesize;
-       char *newname;
-       int fd;
-       size_t readsize;
-       if (!name || !var) return EFI_INVALID_PARAMETER;
-
-       newnamesize = strlen(PROC_DIR_EFI_VARS) + strlen(name) + 1;
-       newname = malloc(newnamesize);
-       if (!newname) return EFI_OUT_OF_RESOURCES;
-       sprintf(newname, "%s%s", PROC_DIR_EFI_VARS,name);
-       fd = open(newname, O_RDONLY);
-       if (fd == -1) {
-               free(newname);
-               return EFI_NOT_FOUND;
+       char name[PATH_MAX];
+       DIR *dir;
+       snprintf(name, PATH_MAX, "%s", SYSFS_DIR_EFI_VARS);
+       dir = opendir(name);
+       if (dir) {
+               closedir(dir);
+               fs_kernel_calls = &sysfs_kernel_calls;
+               return;
        }
-       readsize = read(fd, var, sizeof(*var));
-       if (readsize != sizeof(*var)) {
-               free(newname);
-               close(fd);
-               return EFI_INVALID_PARAMETER;
+
+       snprintf(name, PATH_MAX, "%s", PROCFS_DIR_EFI_VARS);
+       dir = opendir(name);
+       if (dir) {
+               closedir(dir);
+               fs_kernel_calls = &procfs_kernel_calls;
+               return;
        }
-       close(fd);
-       free(newname);
-       return var->Status;
+       fprintf(stderr, "Fatal: Couldn't open either sysfs or procfs directories for accessing EFI variables.\n");
+       fprintf(stderr, "Try 'modprobe efivars' as root.\n");
+       exit(1);
 }
 
+
+
 static efi_status_t
 write_variable_to_file(efi_variable_t *var)
 {
@@ -120,108 +117,72 @@ write_variable_to_file(efi_variable_t *var)
        close(fd);
        return EFI_SUCCESS;
 }
-/**
- * select_variable_names()
- * @d - dirent to compare against
- *
- * This ignores "." and ".." entries, and selects all others.
- */
 
-static int
-select_variable_names(const struct dirent *d)
+efi_status_t
+read_variable(const char *name, efi_variable_t *var)
 {
-       if (!strcmp(d->d_name, ".") ||
-           !strcmp(d->d_name, ".."))
-               return 0;
-       return 1;
+       if (!name || !var) return EFI_INVALID_PARAMETER;
+       return fs_kernel_calls->read(name, var);
 }
 
-/**
- * find_write_victim()
- * @var - variable to be written
- * @file - name of file to open for writing @var is returned.
- *
- * This ignores "." and ".." entries, and selects all others.
- */
-static char *
-find_write_victim(efi_variable_t *var, char file[PATH_MAX])
-{
-       struct dirent **namelist = NULL;
-       int i, n, found=0;
-       char testname[PATH_MAX], *p;
-
-       memset(testname, 0, sizeof(testname));
-       n = scandir(PROC_DIR_EFI_VARS, &namelist,
-                   select_variable_names, alphasort);
-       if (n < 0) {
-               perror("scandir " PROC_DIR_EFI_VARS);
-               fprintf(stderr, "You must 'modprobe efivars' first.\n");
-               return NULL;
-       }
+efi_status_t
+create_variable(efi_variable_t *var)
+{
+       if (!var) return EFI_INVALID_PARAMETER;
+       if (opts.testfile) return write_variable_to_file(var);
+       return fs_kernel_calls->create(var);
+}
 
-       p = testname;
-       efichar_to_char(p, var->VariableName, PATH_MAX);
-       p += strlen(p);
-       p += sprintf(p, "-");
-       efi_guid_unparse(&var->VendorGuid, p);
+efi_status_t
+delete_variable(efi_variable_t *var)
+{
+       if (!var) return EFI_INVALID_PARAMETER;
+       if (opts.testfile) return write_variable_to_file(var);
+       return fs_kernel_calls->delete(var);
+}
 
-       for (i=0; i<n; i++) {
-               if (namelist[i] &&
-                   strncmp(testname, namelist[i]->d_name, sizeof(testname))) {
-                       found++;
-                       sprintf(file, "%s%s", PROC_DIR_EFI_VARS,
-                               namelist[i]->d_name);
-                       break;
-               }
-       }
 
-       while (n--) {
-               if (namelist[n]) {
-                       free(namelist[n]);
-                       namelist[n] = NULL;
-               }
-       }
-       free(namelist);
+efi_status_t
+edit_variable(efi_variable_t *var)
+{
+       char name[PATH_MAX];
+       if (!var) return EFI_INVALID_PARAMETER;
+       if (opts.testfile) return write_variable_to_file(var);
 
-       if (!found) return NULL;
-       return file;
+       variable_to_name(var, name);
+       return fs_kernel_calls->edit(name, var);
 }
 
-
 efi_status_t
-write_variable(efi_variable_t *var)
+create_or_edit_variable(efi_variable_t *var)
 {
-       int fd;
-       size_t writesize;
-       char buffer[PATH_MAX], name[PATH_MAX], *p = NULL;
+       efi_variable_t testvar;
+       char name[PATH_MAX];
 
-       if (!var) return EFI_INVALID_PARAMETER;
-       if (opts.testfile) return write_variable_to_file(var);
-       memset(buffer, 0, sizeof(buffer));
-       memset(name, 0, sizeof(name));
+       memcpy(&testvar, var, sizeof(*var));
+       variable_to_name(var, name);
 
-       p = find_write_victim(var, name);
-       if (!p) return EFI_INVALID_PARAMETER;
+       if (read_variable(name, &testvar) == EFI_SUCCESS)
+               return edit_variable(var);
+       else
+               return create_variable(var);
+}
 
-       fd = open(name, O_WRONLY);
-       if (fd == -1) {
-               sprintf(buffer, "write_variable():open(%s)", name);
-               perror(buffer);
-               return EFI_INVALID_PARAMETER;
-       }
-       writesize = write(fd, var, sizeof(*var));
-       if (writesize != sizeof(*var)) {
-#if 0
-               sprintf(buffer, "write_variable():write(%s)", name);
-               perror(buffer);
-               dump_raw_data(var, sizeof(*var));
-#endif
-               close(fd);
-               return EFI_INVALID_PARAMETER;
+static int
+select_boot_var_names(const struct dirent *d)
+{
+       int num, rc;
+       rc = sscanf(d->d_name, "Boot0%03x-%*s", &num);
+       return rc;
+}
 
-       }
-       close(fd);
-       return EFI_SUCCESS;
+int
+read_boot_var_names(struct dirent ***namelist)
+{
+       if (!fs_kernel_calls || !namelist) return -1;
+       return scandir(fs_kernel_calls->path,
+                      namelist, select_boot_var_names,
+                      alphasort);
 }
 
 
@@ -333,8 +294,55 @@ make_mac_addr_device_path(void *dest, char *mac, uint8_t iftype)
        return p.length;
 }
 
+struct device
+{
+       struct pci_dev *pci_dev;
+       struct list_head node;
+};
+
+static struct device *
+is_parent_bridge(struct pci_dev *p, unsigned int target_bus)
+{
+       struct device *d;
+       unsigned int primary, secondary;
+
+       if ( (pci_read_word(p, PCI_HEADER_TYPE) & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
+               return NULL;
+
+       primary=pci_read_byte(p, PCI_PRIMARY_BUS);
+       secondary=pci_read_byte(p, PCI_SECONDARY_BUS);
+
+
+       if (secondary != target_bus)
+               return NULL;
+
+       d = malloc(sizeof(struct device));
+       if (!d)
+               return NULL;
+       memset(d, 0, sizeof(*d));
+       INIT_LIST_HEAD(&d->node);
+
+       d->pci_dev = p;
+
+       return d;
+}
+
+static struct device *
+find_parent(struct pci_access *pacc, unsigned int target_bus)
+{
+       struct device *dev;
+       struct pci_dev *p;
+
+       for (p=pacc->devices; p; p=p->next) {
+               dev = is_parent_bridge(p, target_bus);
+               if (dev)
+                       return dev;
+       }
+       return NULL;
+}
+
 static uint16_t
-make_pci_device_path(void *dest, uint8_t device, uint8_t function)
+make_one_pci_device_path(void *dest, uint8_t device, uint8_t function)
 {
        PCI_DEVICE_PATH p;
        memset(&p, 0, sizeof(p));
@@ -347,6 +355,47 @@ make_pci_device_path(void *dest, uint8_t device, uint8_t function)
        return p.length;
 }
 
+static uint16_t
+make_pci_device_path(void *dest, uint8_t bus, uint8_t device, uint8_t function)
+{
+       struct device *dev;
+       struct pci_access *pacc;
+       struct list_head *pos, *n;
+       LIST_HEAD(pci_parent_list);
+       char *p = dest;
+
+       pacc = pci_alloc();
+       if (!pacc)
+               return 0;
+
+       pci_init(pacc);
+       pci_scan_bus(pacc);
+
+       do {
+               dev = find_parent(pacc, bus);
+               if (dev) {
+                       list_add(&pci_parent_list, &dev->node);
+                       bus = dev->pci_dev->bus;
+               }
+       } while (dev && bus);
+
+
+       list_for_each_safe(pos, n, &pci_parent_list) {
+               dev = list_entry(pos, struct device, node);
+               p += make_one_pci_device_path(p,
+                                             dev->pci_dev->dev,
+                                             dev->pci_dev->func);
+               list_del(&dev->node);
+               free(dev);
+       }
+
+       p += make_one_pci_device_path(p, device, function);
+
+       pci_cleanup(pacc);
+
+       return ((void *)p - dest);
+}
+
 static uint16_t
 make_scsi_device_path(void *dest, uint16_t id, uint16_t lun)
 {
@@ -423,7 +472,7 @@ make_edd30_device_path(int fd, void *buffer)
        idlun_to_components(&idlun, &host, &channel, &id, &lun);
 
        p += make_acpi_device_path      (p, EISAID_PNP0A03, bus);
-       p += make_pci_device_path       (p, device, function);
+       p += make_pci_device_path       (p, bus, device, function);
        p += make_scsi_device_path      (p, id, lun);
        return ((void *)p - buffer);
 }
@@ -498,7 +547,7 @@ char *make_disk_load_option(char *p, char *disk)
 char *make_net_load_option(char *p, char *iface)
 {
     /* copied pretty much verbatim from the ethtool source */
-    int fd = 0, err;
+    int fd = 0, err; 
     int bus, slot, func;
     struct ifreq ifr;
     struct ethtool_drvinfo drvinfo;
@@ -517,13 +566,14 @@ char *make_net_load_option(char *p, char *iface)
         perror("Cannot get driver information");
     }
 
+
     err = sscanf(drvinfo.bus_info, "%2x:%2x.%x", &bus, &slot, &func);
     if (err == 0) {
         perror("Couldn't parse device location string.");
     }
 
     p += make_acpi_device_path(p, opts.acpi_hid, opts.acpi_uid);
-    p += make_pci_device_path(p, (uint8_t)slot, (uint8_t)func);
+    p += make_pci_device_path(p, bus, (uint8_t)slot, (uint8_t)func);
 
     err = ioctl(fd, SIOCGIFHWADDR, &ifr);
     if (err < 0) {
@@ -532,7 +582,6 @@ char *make_net_load_option(char *p, char *iface)
 
     p += make_mac_addr_device_path(p, ifr.ifr_ifru.ifru_hwaddr.sa_data, 0);
     p += make_end_device_path       (p);
-
     return(p);
 }
 
@@ -690,3 +739,15 @@ make_linux_efi_variable(efi_variable_t *var,
        var->DataSize = load_option_size + opt_data_size;
        return var->DataSize;
 }
+
+
+int
+variable_to_name(efi_variable_t *var, char *name)
+{
+       char *p = name;
+       efichar_to_char(p, var->VariableName, PATH_MAX);
+       p += strlen(p);
+       p += sprintf(p, "-");
+       efi_guid_unparse(&var->VendorGuid, p);
+       return strlen(name);
+}
diff --git a/src/lib/efivars_procfs.c b/src/lib/efivars_procfs.c
new file mode 100644 (file)
index 0000000..2ff5d64
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+  efivars_procfs.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
+
+  Copyright (C) 2001,2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "efi.h"
+#include "efichar.h"
+#include "efibootmgr.h"
+#include "efivars_procfs.h"
+
+static efi_status_t
+procfs_read_variable(const char *name, efi_variable_t *var)
+{
+       char filename[PATH_MAX];
+       int fd;
+       size_t readsize;
+       if (!name || !var) return EFI_INVALID_PARAMETER;
+
+       snprintf(filename, PATH_MAX-1, "%s/%s", PROCFS_DIR_EFI_VARS,name);
+       fd = open(filename, O_RDONLY);
+       if (fd == -1) {
+               return EFI_NOT_FOUND;
+       }
+       readsize = read(fd, var, sizeof(*var));
+       if (readsize != sizeof(*var)) {
+               close(fd);
+               return EFI_INVALID_PARAMETER;
+       }
+       close(fd);
+       return var->Status;
+}
+
+/**
+ * select_variable_names()
+ * @d - dirent to compare against
+ *
+ * This ignores "." and ".." entries, and selects all others.
+ */
+
+static int
+select_variable_names(const struct dirent *d)
+{
+       if (!strcmp(d->d_name, ".") ||
+           !strcmp(d->d_name, ".."))
+               return 0;
+       return 1;
+}
+
+/**
+ * find_write_victim()
+ * @var - variable to be written
+ * @file - name of file to open for writing @var is returned.
+ *
+ * This ignores "." and ".." entries, and selects all others.
+ */
+static char *
+find_write_victim(efi_variable_t *var, char file[PATH_MAX])
+{
+       struct dirent **namelist = NULL;
+       int i, n, found=0;
+       char testname[PATH_MAX], *p;
+
+       memset(testname, 0, sizeof(testname));
+       n = scandir(PROCFS_DIR_EFI_VARS, &namelist,
+                   select_variable_names, alphasort);
+       if (n < 0)
+               return NULL;
+
+       p = testname;
+       efichar_to_char(p, var->VariableName, PATH_MAX);
+       p += strlen(p);
+       p += sprintf(p, "-");
+       efi_guid_unparse(&var->VendorGuid, p);
+
+       for (i=0; i<n; i++) {
+               if (namelist[i] &&
+                   strncmp(testname, namelist[i]->d_name, sizeof(testname))) {
+                       found++;
+                       sprintf(file, "%s/%s", PROCFS_DIR_EFI_VARS,
+                               namelist[i]->d_name);
+                       break;
+               }
+       }
+
+       while (n--) {
+               if (namelist[n]) {
+                       free(namelist[n]);
+                       namelist[n] = NULL;
+               }
+       }
+       free(namelist);
+
+       if (!found) return NULL;
+       return file;
+}
+
+
+static efi_status_t
+procfs_write_variable(efi_variable_t *var)
+{
+       int fd;
+       size_t writesize;
+       char buffer[PATH_MAX], name[PATH_MAX], *p = NULL;
+
+       if (!var) return EFI_INVALID_PARAMETER;
+       memset(buffer, 0, sizeof(buffer));
+       memset(name, 0, sizeof(name));
+
+       p = find_write_victim(var, name);
+       if (!p) return EFI_INVALID_PARAMETER;
+
+       fd = open(name, O_WRONLY);
+       if (fd == -1) {
+               sprintf(buffer, "write_variable():open(%s)", name);
+               perror(buffer);
+               return EFI_INVALID_PARAMETER;
+       }
+       writesize = write(fd, var, sizeof(*var));
+       if (writesize != sizeof(*var)) {
+               close(fd);
+               return EFI_INVALID_PARAMETER;
+
+       }
+       close(fd);
+       return EFI_SUCCESS;
+}
+
+static efi_status_t
+procfs_delete_variable(efi_variable_t *var)
+{
+       if (!var) return EFI_INVALID_PARAMETER;
+       var->DataSize = 0;
+       var->Attributes = 0;
+       return procfs_write_variable(var);
+
+}
+
+static efi_status_t
+procfs_edit_variable(const char *unused, efi_variable_t *var)
+{
+       if (!var) return EFI_INVALID_PARAMETER;
+       return procfs_write_variable(var);
+
+}
+
+struct efivar_kernel_calls procfs_kernel_calls = {
+       .read = procfs_read_variable,
+       .edit = procfs_edit_variable,
+       .create = procfs_write_variable,
+       .delete = procfs_delete_variable,
+       .path = PROCFS_DIR_EFI_VARS,
+};
diff --git a/src/lib/efivars_sysfs.c b/src/lib/efivars_sysfs.c
new file mode 100644 (file)
index 0000000..642c5ad
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+  efivars_sysfs.[ch] - Manipulates EFI variables as exported in /sys/firmware/efi/vars
+
+  Copyright (C) 2001,2003 Dell Computer Corporation <Matt_Domsch@dell.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "efi.h"
+#include "efichar.h"
+#include "efibootmgr.h"
+#include "efivars_sysfs.h"
+
+static efi_status_t
+sysfs_read_variable(const char *name, efi_variable_t *var)
+{
+       char filename[PATH_MAX];
+       int fd;
+       size_t readsize;
+       char buffer[PATH_MAX+40];
+       if (!name || !var) return EFI_INVALID_PARAMETER;
+       memset(buffer, 0, sizeof(buffer));
+
+       snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_DIR_EFI_VARS,name);
+       fd = open(filename, O_RDONLY);
+       if (fd == -1) {
+               return EFI_NOT_FOUND;
+       }
+       readsize = read(fd, var, sizeof(*var));
+       if (readsize != sizeof(*var)) {
+               close(fd);
+               return EFI_INVALID_PARAMETER;
+       }
+       close(fd);
+       return var->Status;
+}
+
+static efi_status_t
+sysfs_write_variable(const char *filename, efi_variable_t *var)
+{
+       int fd;
+       size_t writesize;
+       char buffer[PATH_MAX+40];
+
+       if (!filename || !var) return EFI_INVALID_PARAMETER;
+       memset(buffer, 0, sizeof(buffer));
+
+       fd = open(filename, O_WRONLY);
+       if (fd == -1) {
+               return EFI_INVALID_PARAMETER;
+       }
+       writesize = write(fd, var, sizeof(*var));
+       if (writesize != sizeof(*var)) {
+               close(fd);
+               return EFI_INVALID_PARAMETER;
+       }
+       close(fd);
+       return EFI_SUCCESS;
+}
+
+
+static efi_status_t
+sysfs_edit_variable(const char *name, efi_variable_t *var)
+{
+       char filename[PATH_MAX];
+       if (!var) return EFI_INVALID_PARAMETER;
+       snprintf(filename, PATH_MAX-1, "%s/%s/raw_var", SYSFS_DIR_EFI_VARS,name);
+       return sysfs_write_variable(filename, var);
+}
+
+static efi_status_t
+sysfs_create_variable(efi_variable_t *var)
+{
+       char filename[PATH_MAX];
+       if (!var) return EFI_INVALID_PARAMETER;
+       snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_DIR_EFI_VARS,"new_var");
+       return sysfs_write_variable(filename, var);
+}
+
+static efi_status_t
+sysfs_delete_variable(efi_variable_t *var)
+{
+       char filename[PATH_MAX];
+       if (!var) return EFI_INVALID_PARAMETER;
+       snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_DIR_EFI_VARS,"del_var");
+       return sysfs_write_variable(filename, var);
+}
+
+struct efivar_kernel_calls sysfs_kernel_calls = {
+       .read = sysfs_read_variable,
+       .edit = sysfs_edit_variable,
+       .create = sysfs_create_variable,
+       .delete = sysfs_delete_variable,
+       .path = SYSFS_DIR_EFI_VARS,
+};
index e4985d1353bf401fa9a0f1557ca98717f2c9a855..85aefedd6711f7534f2a59dbd9d519673c7f0461 100644 (file)
@@ -43,7 +43,7 @@
 #define BLKGETLASTSECT  _IO(0x12,108) /* get last sector of block device */
 #define BLKGETSIZE _IO(0x12,96)        /* return device size */
 #define BLKSSZGET  _IO(0x12,104)       /* get block device sector size */
-#define BLKGETSIZE64 _IOR(0x12,114,sizeof(uint64_t))   /* return device size in bytes (u64 *arg) */
+#define BLKGETSIZE64 _IOR(0x12,114,uint64_t)   /* return device size in bytes (u64 *arg) */
 
 struct blkdev_ioctl_param {
         unsigned int block;
index a2f6d49d54e5ed1f8b0bb7205893ebc2f962c6ea..e65a6597653c150337c5ca87a25b1e40a8afff51 100644 (file)
@@ -3,12 +3,13 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "EFIBOOTMGR" "8" "11 August 2003" "" ""
+.TH "EFIBOOTMGR" "8" "06 February 2004" "" ""
+
 .SH NAME
 efibootmgr \- manipulate the EFI Boot Manager
 .SH SYNOPSIS
 
-\fBefibootmgr\fR [ \fB-a\fR]  [ \fB-A\fR]  [ \fB-b \fIXXXX\fB\fR]  [ \fB-B \fIXXXX\fB\fR]  [ \fB-c\fR]  [ \fB-d \fIDISK\fB\fR]  [ \fB-e \fI1|3|-1\fB\fR]  [ \fB-E \fINUM\fB\fR]  [ \fB-g\fR]  [ \fB-H \fIXXXX\fB\fR]  [ \fB-i \fINAME\fB\fR]  [ \fB-l \fINAME\fB\fR]  [ \fB-L \fILABEL\fB\fR]  [ \fB-n \fIXXXX\fB\fR]  [ \fB-N\fR]  [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR]  [ \fB-O\fR]  [ \fB-p \fIPART\fB\fR]  [ \fB-q\fR]  [ \fB-t\fR]  [ \fB-u\fR]  [ \fB-U \fIXXXX\fB\fR]  [ \fB-v\fR]  [ \fB-V\fR]  [ \fB-w\fR] 
+\fBefibootmgr\fR [ \fB-a\fR ] [ \fB-A\fR ] [ \fB-b \fIXXXX\fB\fR ] [ \fB-B \fIXXXX\fB\fR ] [ \fB-c\fR ] [ \fB-d \fIDISK\fB\fR ] [ \fB-e \fI1|3|-1\fB\fR ] [ \fB-E \fINUM\fB\fR ] [ \fB-g\fR ] [ \fB-H \fIXXXX\fB\fR ] [ \fB-i \fINAME\fB\fR ] [ \fB-l \fINAME\fB\fR ] [ \fB-L \fILABEL\fB\fR ] [ \fB-n \fIXXXX\fB\fR ] [ \fB-N\fR ] [ \fB-o \fIXXXX\fB,\fIYYYY\fB,\fIZZZZ\fB\fR\fI ...\fR ] [ \fB-O\fR ] [ \fB-p \fIPART\fB\fR ] [ \fB-q\fR ] [ \fB-t \fIseconds\fB\fR ] [ \fB-T\fR ] [ \fB-u\fR ] [ \fB-U \fIXXXX\fB\fR ] [ \fB-v\fR ] [ \fB-V\fR ] [ \fB-w\fR ]
 
 .SH "DESCRIPTION"
 .PP
@@ -24,7 +25,9 @@ Specification, v1.02 or later, available from:
 .RS
 .B "Note:"
 efibootmgr requires that the kernel support access to EFI
-non-volatile variables (through \fI/proc/efi/vars\fR).
+non-volatile variables (through
+\fI/proc/efi/vars\fR on 2.4 kernels,
+\fI/sys/firmware/efi/vars\fR on 2.6 kernels).
 \fBmodprobe efivars\fR should do the trick.
 .RE
 .SH "OPTIONS"
@@ -89,9 +92,15 @@ Partition number containing the bootloader (defaults to 1)
 \fB-q | --quiet\fR
 Quiet mode - supresses output.
 .TP
-\fB-t | --test \fIfilename\fB\fR
+\fB--test \fIfilename\fB\fR
 Don't write to NVRAM, write to \fIfilename\fR.
 .TP
+\fB-t | --timeout \fIseconds\fB\fR
+Boot Manager timeout, in \fIseconds\fR.
+.TP
+\fB-T | --delete-timeout\fR
+Delete Timeout variable.
+.TP
 \fB-u | --unicode | --UCS-2 \fR
 pass extra command line arguments as UCS-2 (default is
 ASCII)
@@ -108,13 +117,15 @@ Just print version string and exit.
 \fB-w | --write-signature\fR
 write unique signature to the MBR if needed
 .SH "EXAMPLES"
-.TP 1. 
+.TP 3
+1. 
 .SS "DISPLAYING THE CURRENT SETTINGS (MUST BE ROOT)."
 .PP
 [root@localhost ~]# efibootmgr
 BootCurrent: 0004
 BootNext: 0003
 BootOrder: 0004,0000,0001,0002,0003
+Timeout: 30 seconds
 Boot0000* Diskette Drive(device:0)
 Boot0001* CD-ROM Drive(device:FF) 
 Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)   
@@ -140,10 +151,17 @@ deleted by the boot manager after first use.  This allows you
 to change the next boot behavior without changing BootOrder.
 .TP 0.2i
 \(bu
+Timeout - the time in seconds between when the boot
+manager appears on the screen until when it
+automatically chooses the startup value from BootNext
+or BootOrder.
+.TP 0.2i
+\(bu
 Five boot entries (0000 - 0004), along with the active/inactive
 flag (* means active) and the name displayed on the screen.
 .RE
-.TP 2. 
+.TP 3
+2. 
 .SS "CREATING A NEW BOOT OPTION"
 .PP
 An OS installer would call \fBefibootmgr -c\fR.
@@ -152,25 +170,29 @@ Partition, and is mounted at \fI/dev/sda1\fR.  This
 creates a new boot option, called "Linux", and puts it at the top of
 the boot order list.  Options may be passed to modify the default
 behavior.  The default OS Loader is \fIelilo.efi\fR.
-.TP 3. 
+.TP 3
+3. 
 .SS "CHANGING THE BOOT ORDER"
 .PP
 Assuming the configuration in Example #1, 
 \fBefibootmgr -o 3,4\fR could be called to specify
 PXE boot first, then Linux boot.
-.TP 4. 
+.TP 3
+4. 
 .SS "CHANGING THE BOOT ORDER FOR THE NEXT BOOT ONLY"
 .PP
 Assuming the configuration in Example #1, 
 \fBefibootmgr -n 4\fR could be called to specify
 that the Linux entry be taken on next boot.
-.TP 5. 
+.TP 3
+5. 
 .SS "DELETING A BOOT OPTION"
 .PP
 Assuming the configuration in Example #1, 
 \fBefibootmgr -b 4 -B\fR could be called to delete
 entry 4 and remove it from the BootOrder.
-.TP 6. 
+.TP 3
+6. 
 .SS "CREATING NETWORK BOOT ENTRIES"
 .PP
 A system administrator wants to create a boot option to network
index 81c65b94c566d9e254e5c78094d9144d19d33291..0eec0f7dfa5c127159961c73d170fa60f8a30480 100644 (file)
@@ -17,7 +17,7 @@
   <!ENTITY manfirstname "<firstname>dann</firstname>">
   <!ENTITY mansurname   "<surname>frazier</surname>">
   <!-- Please adjust the date whenever revising the manpage. -->
-  <!ENTITY mandate      "<date>2003-08-11</date>">
+  <!ENTITY mandate      "<date>2004-02-05</date>">
   <!-- SECTION should be 1-8, maybe with subsection. Other parameters are
        allowed: see man(7), man(1). -->
   <!ENTITY mansection   "<manvolnum>8</manvolnum>">
@@ -37,7 +37,7 @@
       &mansurname;
     </author>
     <copyright>
-      <year>2002, 2003</year>
+      <year>2002, 2003, 2004</year>
       <holder>&manusername;</holder>
     </copyright>
     &mandate;
@@ -75,7 +75,8 @@
         <arg>-O</arg>
         <arg>-p <replaceable>PART</replaceable></arg>
         <arg>-q</arg>
-        <arg>-t</arg>
+        <arg>-t <replaceable>seconds</replaceable></arg>
+        <arg>-T</arg>
         <arg>-u</arg>
         <arg>-U <replaceable>XXXX</replaceable></arg>
         <arg>-v</arg>
     <note>
       <para>
         &manpackage; requires that the kernel support access to EFI
-        non-volatile variables (through <filename>/proc/efi/vars</filename>).
+        non-volatile variables (through
+        <filename>/proc/efi/vars</filename> on 2.4 kernels,
+        <filename>/sys/firmware/efi/vars</filename> on 2.6 kernels).
         <command>modprobe efivars</command> should do the trick.
       </para>
     </note>
         </listitem>
       </varlistentry>
       <varlistentry>
-        <term><option>-t</option> | <option>--test</option> <replaceable>filename</replaceable></term>
+        <term><option>--test</option> <replaceable>filename</replaceable></term>
         <listitem>
           <para>Don't write to NVRAM, write to <replaceable>filename</replaceable>.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>-t</option> | <option>--timeout</option> <replaceable>seconds</replaceable></term>
+        <listitem>
+          <para>Boot Manager timeout, in <replaceable>seconds</replaceable>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><option>-T</option> | <option>--delete-timeout</option></term>
+        <listitem>
+          <para>Delete Timeout variable.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><option>-u</option> | <option>--unicode</option> | <option>--UCS-2</option> </term>
         <listitem>
   BootCurrent: 0004
   BootNext: 0003
   BootOrder: 0004,0000,0001,0002,0003
+  Timeout: 30 seconds
   Boot0000* Diskette Drive(device:0)
   Boot0001* CD-ROM Drive(device:FF) 
   Boot0002* Hard Drive(Device:80)/HD(Part1,Sig00112233)   
                 to change the next boot behavior without changing BootOrder.
               </para>
             </listitem>
+            <listitem>
+              <para>
+               Timeout - the time in seconds between when the boot
+               manager appears on the screen until when it
+               automatically chooses the startup value from BootNext
+               or BootOrder.
+              </para>
+            </listitem>
             <listitem>
               <para>
                 Five boot entries (0000 - 0004), along with the active/inactive