Imported Debian patch 0.5.3-1
[debian/efibootmgr] / src / lib / efi.c.orig
1 /*
2   efivars_proc.[ch] - Manipulates EFI variables as exported in /proc/efi/vars
3
4   Copyright (C) 2001,2003 Dell Computer Corporation <Matt_Domsch@dell.com>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <stdint.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <linux/sockios.h>
36 #include <net/if.h>
37 #include <pci/pci.h>
38 #include <linux/ethtool.h>
39 #include "efi.h"
40 #include "efichar.h"
41 #include "scsi_ioctls.h"
42 #include "disk.h"
43 #include "efibootmgr.h"
44 #include "efivars_procfs.h"
45 #include "efivars_sysfs.h"
46 #include "list.h"
47
48 static struct efivar_kernel_calls *fs_kernel_calls;
49
50 EFI_DEVICE_PATH *
51 load_option_path(EFI_LOAD_OPTION *option)
52 {
53         char *p = (char *) option;
54         return (EFI_DEVICE_PATH *)
55                 (p + sizeof(uint32_t) /* Attributes */
56                  + sizeof(uint16_t)   /* FilePathListLength*/
57                  + efichar_strsize(option->description)); /* Description */
58 }
59
60 char *
61 efi_guid_unparse(efi_guid_t *guid, char *out)
62 {
63         sprintf(out, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
64                 guid->b[3], guid->b[2], guid->b[1], guid->b[0],
65                 guid->b[5], guid->b[4], guid->b[7], guid->b[6],
66                 guid->b[8], guid->b[9], guid->b[10], guid->b[11],
67                 guid->b[12], guid->b[13], guid->b[14], guid->b[15]);
68         return out;
69 }
70
71 void
72 set_fs_kernel_calls()
73 {
74         char name[PATH_MAX];
75         DIR *dir;
76         snprintf(name, PATH_MAX, "%s", SYSFS_DIR_EFI_VARS);
77         dir = opendir(name);
78         if (dir) {
79                 closedir(dir);
80                 fs_kernel_calls = &sysfs_kernel_calls;
81                 return;
82         }
83
84         snprintf(name, PATH_MAX, "%s", PROCFS_DIR_EFI_VARS);
85         dir = opendir(name);
86         if (dir) {
87                 closedir(dir);
88                 fs_kernel_calls = &procfs_kernel_calls;
89                 return;
90         }
91         fprintf(stderr, "Fatal: Couldn't open either sysfs or procfs directories for accessing EFI variables.\n");
92         fprintf(stderr, "Try 'modprobe efivars' as root.\n");
93         exit(1);
94 }
95
96
97
98 static efi_status_t
99 write_variable_to_file(efi_variable_t *var)
100 {
101         int fd, byteswritten;
102         if (!var || !opts.testfile) return EFI_INVALID_PARAMETER;
103
104         printf("Test mode: Writing to %s\n", opts.testfile);
105         fd = creat(opts.testfile, S_IRWXU);
106         if (fd == -1) {
107                 perror("Couldn't write to testfile");
108                 return EFI_INVALID_PARAMETER;
109         }
110
111         byteswritten = write(fd, var, sizeof(*var));
112         if (byteswritten == -1) {
113                 perror("Writing to testfile");
114
115         }
116         close(fd);
117         return EFI_SUCCESS;
118 }
119
120 efi_status_t
121 read_variable(const char *name, efi_variable_t *var)
122 {
123         if (!name || !var) return EFI_INVALID_PARAMETER;
124         return fs_kernel_calls->read(name, var);
125 }
126
127 efi_status_t
128 create_variable(efi_variable_t *var)
129 {
130         if (!var) return EFI_INVALID_PARAMETER;
131         if (opts.testfile) return write_variable_to_file(var);
132         return fs_kernel_calls->create(var);
133 }
134
135 efi_status_t
136 delete_variable(efi_variable_t *var)
137 {
138         if (!var) return EFI_INVALID_PARAMETER;
139         if (opts.testfile) return write_variable_to_file(var);
140         return fs_kernel_calls->delete(var);
141 }
142
143
144 efi_status_t
145 edit_variable(efi_variable_t *var)
146 {
147         char name[PATH_MAX];
148         if (!var) return EFI_INVALID_PARAMETER;
149         if (opts.testfile) return write_variable_to_file(var);
150
151         variable_to_name(var, name);
152         return fs_kernel_calls->edit(name, var);
153 }
154
155 efi_status_t
156 create_or_edit_variable(efi_variable_t *var)
157 {
158         efi_variable_t testvar;
159         char name[PATH_MAX];
160
161         memcpy(&testvar, var, sizeof(*var));
162         variable_to_name(var, name);
163
164         if (read_variable(name, &testvar) == EFI_SUCCESS)
165                 return edit_variable(var);
166         else
167                 return create_variable(var);
168 }
169
170 static int
171 select_boot_var_names(const struct dirent *d)
172 {
173         if (!strncmp(d->d_name, "Boot", 4) &&
174             isxdigit(d->d_name[4]) && isxdigit(d->d_name[5]) &&
175             isxdigit(d->d_name[6]) && isxdigit(d->d_name[7]) &&
176             d->d_name[8] == '-')
177                 return 1;
178         return 0;
179 }
180
181 int
182 read_boot_var_names(struct dirent ***namelist)
183 {
184         if (!fs_kernel_calls || !namelist) return -1;
185         return scandir(fs_kernel_calls->path,
186                        namelist, select_boot_var_names,
187                        alphasort);
188 }
189
190
191 static int
192 get_edd_version()
193 {
194         efi_status_t status;
195         efi_variable_t var;
196         efi_guid_t guid = BLKX_UNKNOWN_GUID;
197         char name[80], text_guid[40];
198         ACPI_DEVICE_PATH *path = (ACPI_DEVICE_PATH *)&(var.Data);
199         int rc = 0;
200
201         /* Allow global user option override */
202
203         switch (opts.edd_version)
204         {
205         case 0: /* No EDD information */
206                 return 0;
207                 break;
208         case 1: /* EDD 1.0 */
209                 return 1;
210                 break;
211         case 3: /* EDD 3.0 */
212                 return 3;
213                 break;
214         default:
215                 break;
216         }
217
218
219         memset(&var, 0, sizeof(efi_variable_t));
220         efi_guid_unparse(&guid, text_guid);
221         sprintf(name, "blk0-%s", text_guid);
222
223         status = read_variable(name, &var);
224         if (status != EFI_SUCCESS) {
225                 return 0;
226         }
227         if (path->type == 2 && path->subtype == 1) rc = 3;
228         else rc = 1;
229         return rc;
230 }
231
232 /*
233   EFI_DEVICE_PATH, 0x01 (Hardware), 0x04 (Vendor), length 0x0018
234   This needs to know what EFI device has the boot device.
235 */
236 static uint16_t
237 make_edd10_device_path(void *dest, uint32_t hardware_device)
238 {
239         VENDOR_DEVICE_PATH *hw;
240         char buffer[EDD10_HARDWARE_VENDOR_PATH_LENGTH];
241         efi_guid_t guid = EDD10_HARDWARE_VENDOR_PATH_GUID;
242         uint32_t *data;
243         memset(buffer, 0, sizeof(buffer));
244         hw = (VENDOR_DEVICE_PATH *)buffer;
245         data = (uint32_t *)hw->data;
246         hw->type = 0x01; /* Hardware Device Path */
247         hw->subtype = 0x04; /* Vendor */
248         hw->length = EDD10_HARDWARE_VENDOR_PATH_LENGTH;
249         memcpy(&(hw->vendor_guid), &guid, sizeof(guid));
250         *data = hardware_device;
251         memcpy(dest, buffer, hw->length);
252         return hw->length;
253 }
254
255 static uint16_t
256 make_end_device_path(void *dest)
257 {
258         END_DEVICE_PATH p;
259         memset(&p, 0, sizeof(p));
260         p.type = 0x7F; /* End of Hardware Device Path */
261         p.subtype = 0xFF; /* End Entire Device Path */
262         p.length = sizeof(p);
263         memcpy(dest, &p, p.length);
264         return p.length;
265 }
266
267 static uint16_t
268 make_acpi_device_path(void *dest, uint32_t _HID, uint32_t _UID)
269 {
270         ACPI_DEVICE_PATH p;
271         memset(&p, 0, sizeof(p));
272         p.type = 2;
273         p.subtype = 1;
274         p.length = sizeof(p);
275         p._HID = _HID;
276         p._UID = _UID;
277         memcpy(dest, &p, p.length);
278         return p.length;
279 }
280
281 static uint16_t
282 make_mac_addr_device_path(void *dest, char *mac, uint8_t iftype)
283 {
284
285         int i;
286         MAC_ADDR_DEVICE_PATH p;
287         memset(&p, 0, sizeof(p));
288         p.type = 3;
289         p.subtype = 11;
290         p.length = sizeof(p);
291         for (i=0; i < 14; i++) {
292                 p.macaddr[i] = mac[i];
293         }
294         p.iftype = iftype;
295         memcpy(dest, &p, p.length);
296         return p.length;
297 }
298
299 struct device
300 {
301         struct pci_dev *pci_dev;
302         struct list_head node;
303 };
304
305 static struct device *
306 is_parent_bridge(struct pci_dev *p, unsigned int target_bus)
307 {
308         struct device *d;
309         unsigned int primary, secondary;
310
311         if ( (pci_read_word(p, PCI_HEADER_TYPE) & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
312                 return NULL;
313
314         primary=pci_read_byte(p, PCI_PRIMARY_BUS);
315         secondary=pci_read_byte(p, PCI_SECONDARY_BUS);
316
317
318         if (secondary != target_bus)
319                 return NULL;
320
321         d = malloc(sizeof(struct device));
322         if (!d)
323                 return NULL;
324         memset(d, 0, sizeof(*d));
325         INIT_LIST_HEAD(&d->node);
326
327         d->pci_dev = p;
328
329         return d;
330 }
331
332 static struct device *
333 find_parent(struct pci_access *pacc, unsigned int target_bus)
334 {
335         struct device *dev;
336         struct pci_dev *p;
337
338         for (p=pacc->devices; p; p=p->next) {
339                 dev = is_parent_bridge(p, target_bus);
340                 if (dev)
341                         return dev;
342         }
343         return NULL;
344 }
345
346 static uint16_t
347 make_one_pci_device_path(void *dest, uint8_t device, uint8_t function)
348 {
349         PCI_DEVICE_PATH p;
350         memset(&p, 0, sizeof(p));
351         p.type = 1;
352         p.subtype = 1;
353         p.length   = sizeof(p);
354         p.device   = device;
355         p.function = function;
356         memcpy(dest, &p, p.length);
357         return p.length;
358 }
359
360 static uint16_t
361 make_pci_device_path(void *dest, uint8_t bus, uint8_t device, uint8_t function)
362 {
363         struct device *dev;
364         struct pci_access *pacc;
365         struct list_head *pos, *n;
366         LIST_HEAD(pci_parent_list);
367         char *p = dest;
368
369         pacc = pci_alloc();
370         if (!pacc)
371                 return 0;
372
373         pci_init(pacc);
374         pci_scan_bus(pacc);
375
376         do {
377                 dev = find_parent(pacc, bus);
378                 if (dev) {
379                         list_add(&pci_parent_list, &dev->node);
380                         bus = dev->pci_dev->bus;
381                 }
382         } while (dev && bus);
383
384
385         list_for_each_safe(pos, n, &pci_parent_list) {
386                 dev = list_entry(pos, struct device, node);
387                 p += make_one_pci_device_path(p,
388                                               dev->pci_dev->dev,
389                                               dev->pci_dev->func);
390                 list_del(&dev->node);
391                 free(dev);
392         }
393
394         p += make_one_pci_device_path(p, device, function);
395
396         pci_cleanup(pacc);
397
398         return ((void *)p - dest);
399 }
400
401 static uint16_t
402 make_scsi_device_path(void *dest, uint16_t id, uint16_t lun)
403 {
404         SCSI_DEVICE_PATH p;
405         memset(&p, 0, sizeof(p));
406         p.type = 3;
407         p.subtype = 2;
408         p.length   = sizeof(p);
409         p.id       = id;
410         p.lun      = lun;
411         memcpy(dest, &p, p.length);
412         return p.length;
413 }
414
415 static uint16_t
416 make_harddrive_device_path(void *dest, uint32_t num, uint64_t start, uint64_t size,
417                            uint8_t *signature,
418                            uint8_t mbr_type, uint8_t signature_type)
419 {
420         HARDDRIVE_DEVICE_PATH p;
421         memset(&p, 0, sizeof(p));
422         p.type = 4;
423         p.subtype = 1;
424         p.length   = sizeof(p);
425         p.part_num = num;
426         p.start = start;
427         p.size = size;
428         if (signature) memcpy(p.signature, signature, 16);
429         p.mbr_type = mbr_type;
430         p.signature_type = signature_type;
431         memcpy(dest, &p, p.length);
432         return p.length;
433 }
434
435 static uint16_t
436 make_file_path_device_path(void *dest, efi_char16_t *name)
437 {
438         FILE_PATH_DEVICE_PATH *p;
439         char buffer[1024];
440         int namelen  = efichar_strlen(name, -1);
441         int namesize = efichar_strsize(name);
442
443         memset(buffer, 0, sizeof(buffer));
444         p = (FILE_PATH_DEVICE_PATH *)buffer;
445         p->type      = 4;
446         p->subtype   = 4;
447         p->length    = 4 + namesize;
448         efichar_strncpy(p->path_name,
449                         name, namelen);
450
451         memcpy(dest, buffer, p->length);
452         return p->length;
453
454 }
455
456
457
458 static long
459 make_edd30_device_path(int fd, void *buffer)
460 {
461         int rc=0;
462         unsigned char bus=0, device=0, function=0;
463         Scsi_Idlun idlun;
464         unsigned char host=0, channel=0, id=0, lun=0;
465         char *p = buffer;
466
467
468         rc = disk_get_pci(fd, &bus, &device, &function);
469         if (rc) return 0;
470
471         memset(&idlun, 0, sizeof(idlun));
472         rc = get_scsi_idlun(fd, &idlun);
473         if (rc) return 0;
474         idlun_to_components(&idlun, &host, &channel, &id, &lun);
475
476         p += make_acpi_device_path      (p, EISAID_PNP0A03, bus);
477         p += make_pci_device_path       (p, bus, device, function);
478         p += make_scsi_device_path      (p, id, lun);
479         return ((void *)p - buffer);
480 }
481
482 /**
483  * make_disk_load_option()
484  * @disk disk
485  *
486  * Returns 0 on error, length of load option created on success.
487  */
488 char *make_disk_load_option(char *p, char *disk)
489 {
490     int disk_fd=0;
491     char buffer[80];
492     char signature[16];
493     int rc, edd_version=0;
494     uint8_t mbr_type=0, signature_type=0;
495     uint64_t start=0, size=0;
496     efi_char16_t os_loader_path[40];
497
498     memset(signature, 0, sizeof(signature));
499
500     disk_fd = open(opts.disk, O_RDWR);
501     if (disk_fd == -1) {
502         sprintf(buffer, "Could not open disk %s", opts.disk);
503         perror(buffer);
504         return 0;
505     }
506
507     if (opts.edd_version) {
508         edd_version = get_edd_version();
509
510         if (edd_version == 3) {
511             p += make_edd30_device_path(disk_fd, p);
512         }
513         else if (edd_version == 1) {
514             p += make_edd10_device_path(p, opts.edd10_devicenum);
515         }
516     }
517
518     rc = disk_get_partition_info (disk_fd, opts.part,
519                                   &start, &size, signature,
520                                   &mbr_type, &signature_type);
521
522     close(disk_fd);
523
524     if (rc) {
525         fprintf(stderr, "Error: no partition information on disk %s.\n"
526                 "       Cowardly refusing to create a boot option.\n",
527                 opts.disk);
528         return 0;
529     }
530
531     p += make_harddrive_device_path (p, opts.part,
532                                      start, size,
533                                      signature,
534                                      mbr_type, signature_type);
535
536     efichar_from_char(os_loader_path, opts.loader, sizeof(os_loader_path));
537     p += make_file_path_device_path (p, os_loader_path);
538     p += make_end_device_path       (p);
539
540     return(p);
541 }
542
543 /**
544  * make_net_load_option()
545  * @data - load option returned
546  *
547  * Returns NULL on error, or p advanced by length of load option
548  * created on success.
549  */
550 char *make_net_load_option(char *p, char *iface)
551 {
552     /* copied pretty much verbatim from the ethtool source */
553     int fd = 0, err; 
554     int bus, slot, func;
555     struct ifreq ifr;
556     struct ethtool_drvinfo drvinfo;
557
558     memset(&ifr, 0, sizeof(ifr));
559     strcpy(ifr.ifr_name, iface);
560     drvinfo.cmd = ETHTOOL_GDRVINFO;
561     ifr.ifr_data = (caddr_t)&drvinfo;
562     /* Open control socket */
563     fd = socket(AF_INET, SOCK_DGRAM, 0);
564     if (fd < 0) {
565         perror("Cannot get control socket");
566         goto out;
567     }
568     err = ioctl(fd, SIOCETHTOOL, &ifr);
569     if (err < 0) {
570         perror("Cannot get driver information");
571         goto out;
572     }
573
574     /* The domain part was added in 2.6 kernels.  Test for that first. */
575     err = sscanf(drvinfo.bus_info, "%*x:%2x:%2x.%x", &bus, &slot, &func);
576     if (err != 3) {
577             err = sscanf(drvinfo.bus_info, "%2x:%2x.%x", &bus, &slot, &func);
578             if (err != 3) {
579                     perror("Couldn't parse device location string.");
580                     goto out;
581             }
582     }
583
584     err = ioctl(fd, SIOCGIFHWADDR, &ifr);
585     if (err < 0) {
586         perror("Cannot get hardware address.");
587         goto out;
588     }
589
590     p += make_acpi_device_path(p, opts.acpi_hid, opts.acpi_uid);
591     p += make_pci_device_path(p, bus, (uint8_t)slot, (uint8_t)func);
592     p += make_mac_addr_device_path(p, ifr.ifr_ifru.ifru_hwaddr.sa_data, 0);
593     p += make_end_device_path       (p);
594     return(p);
595  out:
596     return NULL;
597 }
598
599 /**
600  * make_linux_load_option()
601  * @data - load option returned
602  *
603  * Returns 0 on error, length of load option created on success.
604  */
605 static unsigned long
606 make_linux_load_option(void *data)
607 {
608         EFI_LOAD_OPTION *load_option = data;
609         char *p = data, *q;
610         efi_char16_t description[64];
611         unsigned long datasize=0;
612
613         /* Write Attributes */
614         if (opts.active) load_option->attributes = LOAD_OPTION_ACTIVE;
615         else             load_option->attributes = 0;
616
617         p += sizeof(uint32_t);
618         /* skip writing file_path_list_length */
619         p += sizeof(uint16_t);
620         /* Write description.  This is the text that appears on the screen for the load option. */
621         memset(description, 0, sizeof(description));
622         efichar_from_char(description, opts.label, sizeof(description));
623         efichar_strncpy(load_option->description, description, sizeof(description));
624         p += efichar_strsize(load_option->description);
625
626         q = p;
627
628         if (opts.iface) {
629               p = (char *)make_net_load_option(p, opts.iface);
630         }
631         else {
632               p = (char *)make_disk_load_option(p, opts.iface);
633         }
634         if (p == NULL)
635                 return 0;
636
637         load_option->file_path_list_length = p - q;
638
639         datasize = (uint8_t *)p - (uint8_t *)data;
640         return datasize;
641 }
642
643 /*
644  * append_extra_args()
645  * appends all arguments from argv[] not snarfed by getopt
646  * as one long string onto data, up to maxchars.  allow for nulls
647  */
648
649 static unsigned long
650 append_extra_args_ascii(void *data, unsigned long maxchars)
651 {
652         char *p = data;
653         int i, appended=0;
654         unsigned long usedchars=0;
655         if (!data) return 0;
656
657
658         for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) {
659                 p = strncpy(p, opts.argv[i], maxchars-usedchars-1);
660                 p += strlen(p);
661                 appended=1;
662
663                 usedchars = p - (char *)data;
664
665                 /* Put a space between args */
666                 if (i < (opts.argc-1)) {
667
668                         p = strncpy(p, " ", maxchars-usedchars-1);
669                         p += strlen(p);
670                         usedchars = p - (char *)data;
671                 }
672
673         }
674         /* Remember the NULL */
675         if (appended) return strlen(data) + 1;
676         return 0;
677 }
678
679 static unsigned long
680 append_extra_args_unicode(void *data, unsigned long maxchars)
681 {
682         char *p = data;
683         int i, appended=0;
684         unsigned long usedchars=0;
685         if (!data) return 0;
686
687
688         for (i=opts.optind; i < opts.argc && usedchars < maxchars; i++) {
689                 p += efichar_from_char((efi_char16_t *)p, opts.argv[i],
690                                        maxchars-usedchars);
691                 usedchars = efichar_strsize(data) - sizeof(efi_char16_t);
692                 appended=1;
693
694                 /* Put a space between args */
695                 if (i < (opts.argc-1)) {
696                         p += efichar_from_char((efi_char16_t *)p, " ",
697                                                maxchars-usedchars);
698                         usedchars = efichar_strsize(data) -
699                                 sizeof(efi_char16_t);
700                 }
701         }
702
703         if (appended) return efichar_strsize( (efi_char16_t *)data );
704         return 0;
705 }
706
707
708 static unsigned long
709 append_extra_args(void *data, unsigned long maxchars)
710 {
711         if (opts.unicode)
712           return append_extra_args_unicode(data, maxchars);
713         else
714           return append_extra_args_ascii(data, maxchars);
715 }
716
717
718
719 int
720 make_linux_efi_variable(efi_variable_t *var,
721                         unsigned int free_number)
722 {
723         efi_guid_t guid = EFI_GLOBAL_VARIABLE;
724         char buffer[16];
725         unsigned char *optional_data=NULL;
726         unsigned long load_option_size = 0, opt_data_size=0;
727
728         memset(buffer,    0, sizeof(buffer));
729
730         /* VariableName needs to be BootXXXX */
731         sprintf(buffer, "Boot%04X", free_number);
732
733         efichar_from_char(var->VariableName, buffer, 1024);
734
735         memcpy(&(var->VendorGuid), &guid, sizeof(guid));
736         var->Attributes =
737                 EFI_VARIABLE_NON_VOLATILE |
738                 EFI_VARIABLE_BOOTSERVICE_ACCESS |
739                 EFI_VARIABLE_RUNTIME_ACCESS;
740
741         /* Set Data[] and DataSize */
742
743         load_option_size =  make_linux_load_option(var->Data);
744
745         if (!load_option_size) return 0;
746
747         /* Set OptionalData (passed as binary to the called app) */
748         optional_data = var->Data + load_option_size;
749         opt_data_size = append_extra_args(optional_data,
750                                   sizeof(var->Data) - load_option_size);
751         var->DataSize = load_option_size + opt_data_size;
752         return var->DataSize;
753 }
754
755
756 int
757 variable_to_name(efi_variable_t *var, char *name)
758 {
759         char *p = name;
760         efichar_to_char(p, var->VariableName, PATH_MAX);
761         p += strlen(p);
762         p += sprintf(p, "-");
763         efi_guid_unparse(&var->VendorGuid, p);
764         return strlen(name);
765 }