X-Git-Url: https://git.gag.com/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Fefi.c.orig;fp=src%2Flib%2Fefi.c.orig;h=0000000000000000000000000000000000000000;hb=438378f384ede73602fcdfd288e45ac41d933bb0;hp=2257e9f960c01d2db51ba774b5a1e33f707e8c3f;hpb=5a32ac6f167fe2ffdd5711ceafe2b39db8ad1ce0;p=debian%2Fefibootmgr diff --git a/src/lib/efi.c.orig b/src/lib/efi.c.orig deleted file mode 100644 index 2257e9f..0000000 --- a/src/lib/efi.c.orig +++ /dev/null @@ -1,765 +0,0 @@ -/* - efivars_proc.[ch] - Manipulates EFI variables as exported in /proc/efi/vars - - Copyright (C) 2001,2003 Dell Computer Corporation - - 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 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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) -{ - char *p = (char *) option; - return (EFI_DEVICE_PATH *) - (p + sizeof(uint32_t) /* Attributes */ - + sizeof(uint16_t) /* FilePathListLength*/ - + efichar_strsize(option->description)); /* Description */ -} - -char * -efi_guid_unparse(efi_guid_t *guid, char *out) -{ - sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->b[3], guid->b[2], guid->b[1], guid->b[0], - guid->b[5], guid->b[4], guid->b[7], guid->b[6], - guid->b[8], guid->b[9], guid->b[10], guid->b[11], - guid->b[12], guid->b[13], guid->b[14], guid->b[15]); - return out; -} - -void -set_fs_kernel_calls() -{ - 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; - } - - snprintf(name, PATH_MAX, "%s", PROCFS_DIR_EFI_VARS); - dir = opendir(name); - if (dir) { - closedir(dir); - fs_kernel_calls = &procfs_kernel_calls; - return; - } - 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) -{ - int fd, byteswritten; - if (!var || !opts.testfile) return EFI_INVALID_PARAMETER; - - printf("Test mode: Writing to %s\n", opts.testfile); - fd = creat(opts.testfile, S_IRWXU); - if (fd == -1) { - perror("Couldn't write to testfile"); - return EFI_INVALID_PARAMETER; - } - - byteswritten = write(fd, var, sizeof(*var)); - if (byteswritten == -1) { - perror("Writing to testfile"); - - } - close(fd); - return EFI_SUCCESS; -} - -efi_status_t -read_variable(const char *name, efi_variable_t *var) -{ - if (!name || !var) return EFI_INVALID_PARAMETER; - return fs_kernel_calls->read(name, var); -} - -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); -} - -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); -} - - -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); - - variable_to_name(var, name); - return fs_kernel_calls->edit(name, var); -} - -efi_status_t -create_or_edit_variable(efi_variable_t *var) -{ - efi_variable_t testvar; - char name[PATH_MAX]; - - memcpy(&testvar, var, sizeof(*var)); - variable_to_name(var, name); - - if (read_variable(name, &testvar) == EFI_SUCCESS) - return edit_variable(var); - else - return create_variable(var); -} - -static int -select_boot_var_names(const struct dirent *d) -{ - if (!strncmp(d->d_name, "Boot", 4) && - isxdigit(d->d_name[4]) && isxdigit(d->d_name[5]) && - isxdigit(d->d_name[6]) && isxdigit(d->d_name[7]) && - d->d_name[8] == '-') - return 1; - return 0; -} - -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); -} - - -static int -get_edd_version() -{ - efi_status_t status; - efi_variable_t var; - efi_guid_t guid = BLKX_UNKNOWN_GUID; - char name[80], text_guid[40]; - ACPI_DEVICE_PATH *path = (ACPI_DEVICE_PATH *)&(var.Data); - int rc = 0; - - /* Allow global user option override */ - - switch (opts.edd_version) - { - case 0: /* No EDD information */ - return 0; - break; - case 1: /* EDD 1.0 */ - return 1; - break; - case 3: /* EDD 3.0 */ - return 3; - break; - default: - break; - } - - - memset(&var, 0, sizeof(efi_variable_t)); - efi_guid_unparse(&guid, text_guid); - sprintf(name, "blk0-%s", text_guid); - - status = read_variable(name, &var); - if (status != EFI_SUCCESS) { - return 0; - } - if (path->type == 2 && path->subtype == 1) rc = 3; - else rc = 1; - return rc; -} - -/* - EFI_DEVICE_PATH, 0x01 (Hardware), 0x04 (Vendor), length 0x0018 - This needs to know what EFI device has the boot device. -*/ -static uint16_t -make_edd10_device_path(void *dest, uint32_t hardware_device) -{ - VENDOR_DEVICE_PATH *hw; - char buffer[EDD10_HARDWARE_VENDOR_PATH_LENGTH]; - efi_guid_t guid = EDD10_HARDWARE_VENDOR_PATH_GUID; - uint32_t *data; - memset(buffer, 0, sizeof(buffer)); - hw = (VENDOR_DEVICE_PATH *)buffer; - data = (uint32_t *)hw->data; - hw->type = 0x01; /* Hardware Device Path */ - hw->subtype = 0x04; /* Vendor */ - hw->length = EDD10_HARDWARE_VENDOR_PATH_LENGTH; - memcpy(&(hw->vendor_guid), &guid, sizeof(guid)); - *data = hardware_device; - memcpy(dest, buffer, hw->length); - return hw->length; -} - -static uint16_t -make_end_device_path(void *dest) -{ - END_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 0x7F; /* End of Hardware Device Path */ - p.subtype = 0xFF; /* End Entire Device Path */ - p.length = sizeof(p); - memcpy(dest, &p, p.length); - return p.length; -} - -static uint16_t -make_acpi_device_path(void *dest, uint32_t _HID, uint32_t _UID) -{ - ACPI_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 2; - p.subtype = 1; - p.length = sizeof(p); - p._HID = _HID; - p._UID = _UID; - memcpy(dest, &p, p.length); - return p.length; -} - -static uint16_t -make_mac_addr_device_path(void *dest, char *mac, uint8_t iftype) -{ - - int i; - MAC_ADDR_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 3; - p.subtype = 11; - p.length = sizeof(p); - for (i=0; i < 14; i++) { - p.macaddr[i] = mac[i]; - } - p.iftype = iftype; - memcpy(dest, &p, p.length); - 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_one_pci_device_path(void *dest, uint8_t device, uint8_t function) -{ - PCI_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 1; - p.subtype = 1; - p.length = sizeof(p); - p.device = device; - p.function = function; - memcpy(dest, &p, p.length); - 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) -{ - SCSI_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 3; - p.subtype = 2; - p.length = sizeof(p); - p.id = id; - p.lun = lun; - memcpy(dest, &p, p.length); - return p.length; -} - -static uint16_t -make_harddrive_device_path(void *dest, uint32_t num, uint64_t start, uint64_t size, - uint8_t *signature, - uint8_t mbr_type, uint8_t signature_type) -{ - HARDDRIVE_DEVICE_PATH p; - memset(&p, 0, sizeof(p)); - p.type = 4; - p.subtype = 1; - p.length = sizeof(p); - p.part_num = num; - p.start = start; - p.size = size; - if (signature) memcpy(p.signature, signature, 16); - p.mbr_type = mbr_type; - p.signature_type = signature_type; - memcpy(dest, &p, p.length); - return p.length; -} - -static uint16_t -make_file_path_device_path(void *dest, efi_char16_t *name) -{ - FILE_PATH_DEVICE_PATH *p; - char buffer[1024]; - int namelen = efichar_strlen(name, -1); - int namesize = efichar_strsize(name); - - memset(buffer, 0, sizeof(buffer)); - p = (FILE_PATH_DEVICE_PATH *)buffer; - p->type = 4; - p->subtype = 4; - p->length = 4 + namesize; - efichar_strncpy(p->path_name, - name, namelen); - - memcpy(dest, buffer, p->length); - return p->length; - -} - - - -static long -make_edd30_device_path(int fd, void *buffer) -{ - int rc=0; - unsigned char bus=0, device=0, function=0; - Scsi_Idlun idlun; - unsigned char host=0, channel=0, id=0, lun=0; - char *p = buffer; - - - rc = disk_get_pci(fd, &bus, &device, &function); - if (rc) return 0; - - memset(&idlun, 0, sizeof(idlun)); - rc = get_scsi_idlun(fd, &idlun); - if (rc) return 0; - idlun_to_components(&idlun, &host, &channel, &id, &lun); - - p += make_acpi_device_path (p, EISAID_PNP0A03, bus); - p += make_pci_device_path (p, bus, device, function); - p += make_scsi_device_path (p, id, lun); - return ((void *)p - buffer); -} - -/** - * make_disk_load_option() - * @disk disk - * - * Returns 0 on error, length of load option created on success. - */ -char *make_disk_load_option(char *p, char *disk) -{ - int disk_fd=0; - char buffer[80]; - char signature[16]; - int rc, edd_version=0; - uint8_t mbr_type=0, signature_type=0; - uint64_t start=0, size=0; - efi_char16_t os_loader_path[40]; - - memset(signature, 0, sizeof(signature)); - - disk_fd = open(opts.disk, O_RDWR); - if (disk_fd == -1) { - sprintf(buffer, "Could not open disk %s", opts.disk); - perror(buffer); - return 0; - } - - if (opts.edd_version) { - edd_version = get_edd_version(); - - if (edd_version == 3) { - p += make_edd30_device_path(disk_fd, p); - } - else if (edd_version == 1) { - p += make_edd10_device_path(p, opts.edd10_devicenum); - } - } - - rc = disk_get_partition_info (disk_fd, opts.part, - &start, &size, signature, - &mbr_type, &signature_type); - - close(disk_fd); - - if (rc) { - fprintf(stderr, "Error: no partition information on disk %s.\n" - " Cowardly refusing to create a boot option.\n", - opts.disk); - return 0; - } - - p += make_harddrive_device_path (p, opts.part, - start, size, - signature, - mbr_type, signature_type); - - efichar_from_char(os_loader_path, opts.loader, sizeof(os_loader_path)); - p += make_file_path_device_path (p, os_loader_path); - p += make_end_device_path (p); - - return(p); -} - -/** - * make_net_load_option() - * @data - load option returned - * - * Returns NULL on error, or p advanced by length of load option - * created on success. - */ -char *make_net_load_option(char *p, char *iface) -{ - /* copied pretty much verbatim from the ethtool source */ - int fd = 0, err; - int bus, slot, func; - struct ifreq ifr; - struct ethtool_drvinfo drvinfo; - - memset(&ifr, 0, sizeof(ifr)); - strcpy(ifr.ifr_name, iface); - drvinfo.cmd = ETHTOOL_GDRVINFO; - ifr.ifr_data = (caddr_t)&drvinfo; - /* Open control socket */ - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - perror("Cannot get control socket"); - goto out; - } - err = ioctl(fd, SIOCETHTOOL, &ifr); - if (err < 0) { - perror("Cannot get driver information"); - goto out; - } - - /* The domain part was added in 2.6 kernels. Test for that first. */ - err = sscanf(drvinfo.bus_info, "%*x:%2x:%2x.%x", &bus, &slot, &func); - if (err != 3) { - err = sscanf(drvinfo.bus_info, "%2x:%2x.%x", &bus, &slot, &func); - if (err != 3) { - perror("Couldn't parse device location string."); - goto out; - } - } - - err = ioctl(fd, SIOCGIFHWADDR, &ifr); - if (err < 0) { - perror("Cannot get hardware address."); - goto out; - } - - p += make_acpi_device_path(p, opts.acpi_hid, opts.acpi_uid); - p += make_pci_device_path(p, bus, (uint8_t)slot, (uint8_t)func); - p += make_mac_addr_device_path(p, ifr.ifr_ifru.ifru_hwaddr.sa_data, 0); - p += make_end_device_path (p); - return(p); - out: - return NULL; -} - -/** - * make_linux_load_option() - * @data - load option returned - * - * Returns 0 on error, length of load option created on success. - */ -static unsigned long -make_linux_load_option(void *data) -{ - EFI_LOAD_OPTION *load_option = data; - char *p = data, *q; - efi_char16_t description[64]; - unsigned long datasize=0; - - /* Write Attributes */ - if (opts.active) load_option->attributes = LOAD_OPTION_ACTIVE; - else load_option->attributes = 0; - - p += sizeof(uint32_t); - /* skip writing file_path_list_length */ - p += sizeof(uint16_t); - /* Write description. This is the text that appears on the screen for the load option. */ - memset(description, 0, sizeof(description)); - efichar_from_char(description, opts.label, sizeof(description)); - efichar_strncpy(load_option->description, description, sizeof(description)); - p += efichar_strsize(load_option->description); - - q = p; - - if (opts.iface) { - p = (char *)make_net_load_option(p, opts.iface); - } - else { - p = (char *)make_disk_load_option(p, opts.iface); - } - if (p == NULL) - return 0; - - load_option->file_path_list_length = p - q; - - datasize = (uint8_t *)p - (uint8_t *)data; - return datasize; -} - -/* - * append_extra_args() - * appends all arguments from argv[] not snarfed by getopt - * as one long string onto data, up to maxchars. allow for nulls - */ - -static unsigned long -append_extra_args_ascii(void *data, unsigned long maxchars) -{ - char *p = data; - int i, appended=0; - unsigned long usedchars=0; - if (!data) return 0; - - - for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) { - p = strncpy(p, opts.argv[i], maxchars-usedchars-1); - p += strlen(p); - appended=1; - - usedchars = p - (char *)data; - - /* Put a space between args */ - if (i < (opts.argc-1)) { - - p = strncpy(p, " ", maxchars-usedchars-1); - p += strlen(p); - usedchars = p - (char *)data; - } - - } - /* Remember the NULL */ - if (appended) return strlen(data) + 1; - return 0; -} - -static unsigned long -append_extra_args_unicode(void *data, unsigned long maxchars) -{ - char *p = data; - int i, appended=0; - unsigned long usedchars=0; - if (!data) return 0; - - - for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) { - p += efichar_from_char((efi_char16_t *)p, opts.argv[i], - maxchars-usedchars); - usedchars = efichar_strsize(data) - sizeof(efi_char16_t); - appended=1; - - /* Put a space between args */ - if (i < (opts.argc-1)) { - p += efichar_from_char((efi_char16_t *)p, " ", - maxchars-usedchars); - usedchars = efichar_strsize(data) - - sizeof(efi_char16_t); - } - } - - if (appended) return efichar_strsize( (efi_char16_t *)data ); - return 0; -} - - -static unsigned long -append_extra_args(void *data, unsigned long maxchars) -{ - if (opts.unicode) - return append_extra_args_unicode(data, maxchars); - else - return append_extra_args_ascii(data, maxchars); -} - - - -int -make_linux_efi_variable(efi_variable_t *var, - unsigned int free_number) -{ - efi_guid_t guid = EFI_GLOBAL_VARIABLE; - char buffer[16]; - unsigned char *optional_data=NULL; - unsigned long load_option_size = 0, opt_data_size=0; - - memset(buffer, 0, sizeof(buffer)); - - /* VariableName needs to be BootXXXX */ - sprintf(buffer, "Boot%04X", free_number); - - efichar_from_char(var->VariableName, buffer, 1024); - - memcpy(&(var->VendorGuid), &guid, sizeof(guid)); - var->Attributes = - EFI_VARIABLE_NON_VOLATILE | - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS; - - /* Set Data[] and DataSize */ - - load_option_size = make_linux_load_option(var->Data); - - if (!load_option_size) return 0; - - /* Set OptionalData (passed as binary to the called app) */ - optional_data = var->Data + load_option_size; - opt_data_size = append_extra_args(optional_data, - sizeof(var->Data) - load_option_size); - 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); -}