Imported Debian patch 3.6-1
[debian/elilo] / fileops.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *
5  * This file is part of the ELILO, the EFI Linux boot loader.
6  *
7  *  ELILO is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2, or (at your option)
10  *  any later version.
11  *
12  *  ELILO is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with ELILO; see the file COPYING.  If not, write to the Free
19  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20  *  02111-1307, USA.
21  *
22  * Please check out the elilo.txt for complete documentation on how
23  * to use this program.
24  */
25
26 #include <efi.h>
27 #include <efilib.h>
28
29 #include "elilo.h"
30 #include "fileops.h"
31
32 /*
33  * import filesystems
34  */
35 #ifdef CONFIG_LOCALFS
36 #include "glue_localfs.h"
37 #endif
38 #ifdef CONFIG_NETFS
39 #include "glue_netfs.h"
40 #endif
41
42 #ifdef CONFIG_EXT2FS
43 #include "glue_ext2fs.h"
44 #endif
45
46 /*
47  * table of device naming schemes.
48  * we will probe each one in sequential order and stop at first match.
49  */
50 extern devname_scheme_t simple_devname_scheme;
51
52 static devname_scheme_t *devname_scheme_tab[]={
53         &simple_devname_scheme,
54         NULL
55 };
56
57
58 /*
59  * Once we are able to create Boot Services drivers we won't need
60  * this hack and we'll be able to load the driver from the boot manager
61  * or EFI shell. So for now we explicitely invoke the probe routine
62  * of each driver that we know about
63  */
64
65 typedef EFI_STATUS (fops_fixups_t)(EFI_HANDLE dev, device_t *d);
66
67 /*
68  * List of filesystem we currently support
69  */
70
71
72 static fileops_fs_t *fs_tab[]={
73 #ifdef CONFIG_LOCALFS
74         &localfs_glue, 
75 #endif
76 #ifdef CONFIG_EXT2FS
77         &ext2fs_glue,
78 #endif
79 #ifdef CONFIG_NETFS
80         &netfs_glue, 
81 #endif
82         NULL
83 };
84
85 static device_t *dev_tab;
86 static UINTN ndev, ndev_boot;
87 static device_t *boot_dev;
88
89 typedef struct _fdesc_t {
90         struct _fdesc_t *next;  /* pointer to next free (when in free list) */
91         fileops_t       *fops;  /* pointer to filesystem-specific glue interface */
92         UINTN           fh;     /* file descriptor from lower level protocol */
93 } fdesc_t;
94
95 #define FILEOPS_FD_MAX  16
96
97 static fdesc_t fd_tab[FILEOPS_FD_MAX];
98 static fdesc_t *free_fd;
99
100 static devname_scheme_t *current_devname_scheme;
101
102 #define FDESC_IDX(f)    (fops_fd_t)(f-fd_tab)
103 #define FDESC_INVALID_FD(fd)    (fd >= FILEOPS_FD_MAX || fd_tab[(fd)].fops == NULL)
104 #define FDESC_F(fd)             (fd_tab+(fd))
105
106 static fdesc_t *
107 fd_alloc(VOID)
108 {
109         fdesc_t *tmp = NULL;
110
111         if (free_fd == NULL) {
112                 ERR_PRT((L"out of file descriptor"));
113         } else {
114                 tmp = free_fd;
115                 free_fd = free_fd->next;
116         }
117         return tmp;
118 }
119
120 static VOID
121 fd_free(fdesc_t *fd)
122 {
123         if (fd == NULL) {
124                 ERR_PRT((L"invalid fd"));
125         }
126         fd->fops = NULL; /* mark as invalid */
127         fd->next = free_fd;
128         free_fd = fd;
129 }
130
131 static fileops_t *
132 glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue)
133 {
134         fileops_t *fops;
135         VOID *intf = NULL;
136         EFI_STATUS status;
137
138         status = BS->HandleProtocol(dev, proto, &intf);
139         if (EFI_ERROR(status)) {
140                 ERR_PRT((L"unable to locate %g: should not happen", proto));
141                 return NULL; /* should not happen */
142         }
143         fops = (fileops_t *)alloc(sizeof(*fops), EfiLoaderData);
144         if (fops == NULL) {
145                 ERR_PRT((L"failed to allocate fileops"));
146                 return NULL; /* XXX uninstall protocol */
147         }
148         Memset(fops, 0, sizeof(*fops));
149
150         fops->dev = dev;
151
152         /* initialize private interface now */
153         glue(fops, intf);
154
155         return fops;
156 }
157
158 INTN
159 fops_split_path(CHAR16 *path, CHAR16 *dev)
160 {
161         CHAR16 *p, *d = dev;
162         UINTN len = FILEOPS_DEVNAME_MAXLEN;
163 #       define CHAR_COLON       L':'
164
165         p = StrChr(path, CHAR_COLON);
166         if (p == NULL) {
167                 *dev = CHAR_NULL; 
168                 return 0;
169         }
170         /* copy device part of the name */
171         for (d = dev ; path != p ;) {
172                 if (--len == 0) return -1; /* too long */
173                 *d++ = *path++;
174         }
175         *d = CHAR_NULL;
176         return 0;
177 }
178
179 static device_t *
180 find_device_byname(CHAR16 *dev)
181 {
182         UINTN i;
183         for(i=0; i < ndev; i++) {
184                 if (!StrCmp(dev, dev_tab[i].name)) return dev_tab+i;
185         }
186         return NULL;
187 }
188
189
190 /*
191  * This function is used to walk through the device list and get names.
192  * arguments:
193  *      - pidx = opaque cookie returned by previous call (must be zero for initial call)
194  *      - type is the type of filesystem to look for, e.g., vfat or ext2fs. NULL means ANY
195  *      - maxlen is the size in bytes of the returned string buffer
196  *      - idx is the opaque cookie returned (can be reused by next call)
197  *      - name a string buffer to hold the name of the next matching device
198  *      - dev will receive the EFI_HANDLE corresponding to the device  if not NULL
199  *
200  * return:
201  *      - EFI_INVALID_PARAMETER: when NULL values are passed for required arguments.
202  *      - EFI_NOT_FOUND: when reached the end of the list of invalid cookie
203  *      - EFI_BUFFER_TOO_SMALL is device name does not fit into string buffer
204  *      - EFI_SUCCESS otherwise
205  */
206 EFI_STATUS
207 fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev)
208 {
209         UINTN i;
210
211         if (name == NULL || idx == NULL) return EFI_INVALID_PARAMETER;
212
213         for(i=pidx; i < ndev; i++) {
214                 if (type == NULL || !StrCmp(dev_tab[i].fops->name, type)) goto found;
215         }
216         return EFI_NOT_FOUND;
217 found:
218         if (StrLen(dev_tab[i].name) >= maxlen) {
219                 *idx = pidx; /* will restart from same place! */
220                 return EFI_BUFFER_TOO_SMALL;
221         }
222         StrCpy(name, dev_tab[i].name);
223         *idx = i+1;
224         if (dev) *dev = dev_tab[i].dev; 
225
226         return EFI_SUCCESS;
227 }
228
229 EFI_STATUS
230 fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev)
231 {
232         UINTN i;
233
234         if (name == NULL || dev == NULL) return EFI_INVALID_PARAMETER;
235
236         for(i=0; i < ndev; i++) {
237                 if (!StrCmp(dev_tab[i].name, name)) goto found;
238         }
239         return EFI_NOT_FOUND;
240 found:
241         *dev = dev_tab[i].dev; 
242
243         return EFI_SUCCESS;
244 }
245
246
247 EFI_STATUS
248 fops_open(CHAR16 *fullname, fops_fd_t *fd)
249 {
250         fdesc_t *f;
251         EFI_STATUS status;
252         fileops_t *fops;
253         device_t *dev;
254         CHAR16 dev_name[FILEOPS_DEVNAME_MAXLEN];
255         CHAR16 *name;
256
257
258         if (fd == NULL || fullname == NULL || *fullname == CHAR_NULL || fops_split_path(fullname, dev_name) == -1) 
259                 return EFI_INVALID_PARAMETER;
260
261         DBG_PRT((L"fops_open(%s), dev:%s:", fullname ? fullname : L"(NULL)", dev_name));
262
263         name = fullname;
264         if (dev_name[0] == CHAR_NULL) {
265                 if (boot_dev == NULL) return EFI_INVALID_PARAMETER;
266                 fops = boot_dev->fops;
267         } else {
268                 if ((dev=find_device_byname(dev_name)) == NULL) return EFI_INVALID_PARAMETER;
269
270                 name += StrLen(dev_name)+1;
271
272                 fops = dev->fops;
273         }
274
275         if (fops == NULL) return EFI_INVALID_PARAMETER;
276
277         if ((f=fd_alloc()) == NULL) return EFI_OUT_OF_RESOURCES;
278
279         DBG_PRT((L"dev:%s: fullname:%s: name:%s: f=%d", dev_name, fullname, name, f - fd_tab));
280
281         status = fops->open(fops->intf, name, &f->fh);
282         if (EFI_ERROR(status)) goto error;
283
284         f->fops = fops;
285
286         *fd = FDESC_IDX(f);
287
288         return EFI_SUCCESS;
289 error:
290         fd_free(f);
291         return status;
292 }
293
294 EFI_STATUS
295 fops_read(fops_fd_t fd, VOID *buf, UINTN *size)
296 {
297         fdesc_t *f;
298
299         if (buf == NULL || FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
300
301         f = FDESC_F(fd);
302
303         return f->fops->read(f->fops->intf, f->fh, buf, size);
304 }
305
306 EFI_STATUS
307 fops_close(fops_fd_t fd)
308 {
309         fdesc_t *f;
310         EFI_STATUS status;
311
312         if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
313
314         f = FDESC_F(fd);
315
316         status = f->fops->close(f->fops->intf, f->fh);
317
318         fd_free(f);
319
320         return status;
321 }
322
323 EFI_STATUS
324 fops_infosize(fops_fd_t fd, UINT64 *size)
325 {
326         fdesc_t *f;
327
328         if (FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
329
330         f = FDESC_F(fd);
331
332         return f->fops->infosize(f->fops->intf, f->fh, size);
333 }
334
335 EFI_STATUS
336 fops_seek(fops_fd_t fd, UINT64 newpos)
337 {
338         fdesc_t *f;
339
340         if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
341
342         f = FDESC_F(fd);
343
344         return f->fops->seek(f->fops->intf, f->fh, newpos);
345 }
346
347 EFI_STATUS
348 fops_setdefaults(struct config_file *defconf, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
349 {
350     INTN i;
351
352 /*
353  * The first default config file is architecture dependent. This is useful
354  * in case of network booting where the server is used for both types of
355  * architectures.
356  */
357 #if defined(CONFIG_ia64)
358 #define FILEOPS_ARCH_DEFAULT_CONFIG     L"elilo-ia64.conf"
359 #elif defined (CONFIG_ia32)
360 #define FILEOPS_ARCH_DEFAULT_CONFIG     L"elilo-ia32.conf"
361 #else
362 #error "You need to specfy your default arch config file"
363 #endif
364
365 /* 
366  * last resort config file. Common to all architectures
367  */
368 #define FILEOPS_DEFAULT_CONFIG  L"elilo.conf"
369
370 #define FILEOPS_DEFAULT_KERNEL          L"vmlinux"
371
372 #ifdef ELILO_DEBUG
373         if (defconf == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
374 #endif
375
376         for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
377             defconf[i].fname[0] = CHAR_NULL;
378         }
379
380         if (boot_dev == NULL || boot_dev->fops == NULL) {
381                 if (boot_dev == NULL) 
382                         Print(L"Warning boot device not recognized\n");
383                 else
384                         Print(L"Unknown filesystem on boot device\n");
385
386                 Print(L"Using builtin defaults for kernel and config file\n");
387
388                 StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
389         }
390         else {
391                 boot_dev->fops->setdefaults(boot_dev->fops->intf, defconf, kname, maxlen, devpath);
392         }
393         i=0; while (i<MAX_DEFAULT_CONFIGS && defconf[i].fname[0] != CHAR_NULL) i += 1;
394 #ifdef ELILO_DEBUG
395         if ((i+3) >= MAX_DEFAULT_CONFIGS) {
396             Print(L"ERROR: i = %d, MAX_DEFAULT_CONFIGS is not large enough\n", i);
397             return EFI_INVALID_PARAMETER;
398         }
399 #endif
400         StrnCpy(defconf[i].fname, FILEOPS_ARCH_DEFAULT_CONFIG, maxlen-1);
401         StrnCpy(defconf[i+1].fname, FILEOPS_DEFAULT_CONFIG, maxlen-1);
402
403 #ifdef ELILO_DEBUG
404         VERB_PRT(3,Print(L"Default config filename list:\n"));
405         for (i=0; i<MAX_DEFAULT_CONFIGS; i++) {
406                 if (defconf[i].fname[0] == CHAR_NULL) { break; }
407                         VERB_PRT(3,Print(L"\t%s\n", defconf[i].fname));
408         }
409 #endif
410         
411         return EFI_SUCCESS;
412 }
413
414 EFI_STATUS
415 fops_getdefault_path(CHAR16 *path, UINTN maxlen)
416 {
417         if (path == NULL || maxlen == 0) return EFI_INVALID_PARAMETER;
418
419         /*
420          * if underlying filesystem implements the call, then we call
421          * otherwise we return an empty string
422          */
423         if (boot_dev->fops->getdefault_path) 
424                 return boot_dev->fops->getdefault_path(path, maxlen);
425
426         path[0] = CHAR_NULL;
427
428         return EFI_SUCCESS;
429 }
430
431 CHAR16 *
432 fops_bootdev_name(VOID)
433 {
434         return boot_dev ? boot_dev->name : L"not supported";
435 }
436
437 static INTN
438 add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t glue)
439 {
440         EFI_STATUS status;
441         EFI_HANDLE *tab;
442         UINTN i;
443         static UINTN idx;
444
445         if (size == 0) return 0;
446
447         tab = (EFI_HANDLE *)alloc(size, EfiLoaderData);
448         if (tab == NULL) {
449                 ERR_PRT((L"failed to allocate handle table"));
450                 return -1;
451         }
452
453         Memset(tab, 0, size);
454
455         /*
456          * get the actual device handles now
457          */
458         status = BS->LocateHandle(ByProtocol, proto, NULL, &size, tab);
459         if (status != EFI_SUCCESS) {
460                 ERR_PRT((L"failed to get handles for proto %g size=%d: %r", proto, size, status));
461                 free(tab);
462                 return -1;
463         }
464         size /= sizeof(EFI_HANDLE);
465
466         for(i=0; i < size; i++) {
467                 dev_tab[idx].dev  = tab[i];
468                 dev_tab[idx].fops = glue_filesystem(proto, tab[i], glue);
469
470                 if (tab[i] == boot_handle) boot_dev = dev_tab+idx;
471
472                 /* count the ones we recognized */
473                 if (dev_tab[idx].fops) ndev_boot++;
474
475                 /* assign a generic name for now */
476                 dev_tab[idx].name[0] = L'd';
477                 dev_tab[idx].name[1] = L'e';
478                 dev_tab[idx].name[2] = L'v';
479                 dev_tab[idx].name[3] = L'0' + idx/100;
480                 dev_tab[idx].name[4] = L'0' + (idx%100)/10;
481                 dev_tab[idx].name[5] = L'0' + (idx%100) % 10;
482                 dev_tab[idx].name[6] = CHAR_NULL;
483  
484 #ifdef ELILO_DEBUG
485                 if (elilo_opt.debug) {
486                         EFI_DEVICE_PATH *dp;
487                         CHAR16 *str, *str2;
488                                 
489                         str = NULL;
490                         dp = DevicePathFromHandle(dev_tab[idx].dev);
491                         if (dp) str = DevicePathToStr(dp);
492
493                         str2 = str == NULL ? L"Unknown" : str;
494
495                         DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name,
496                                 (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2));
497
498                         if (str) FreePool(str);
499                 }
500 #endif
501
502                 idx++;
503         }
504         free(tab);
505
506         /* remember actual number of bootable devices */
507         ndev = idx;
508
509         return 0;
510 }
511
512 static INTN
513 probe_devname_schemes(device_t *dev_tab, INTN ndev)
514 {
515         devname_scheme_t **p;
516
517         for (p = devname_scheme_tab; *p ; p++) {
518                 if ((*p)->install_scheme(dev_tab, ndev) == 0) goto found;
519         }
520         ERR_PRT((L"No devname schemes worked, using builtin\n"));
521         return -1;
522 found:
523         VERB_PRT(3, Print(L"devname scheme: %s\n", (*p)->name));
524         current_devname_scheme = *p;
525         return 0;
526 }
527
528 static INTN
529 find_filesystems(EFI_HANDLE boot_handle)
530 {
531         UINTN size, total = 0;
532         fileops_fs_t **fs;
533
534         /*
535          * 1st pass, figure out how big a table we need
536          */
537         for(fs = fs_tab; *fs; fs++) {
538                 size = 0;
539                 BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
540                 total += size;
541         }
542         if (total == 0) {
543                 ERR_PRT((L"No useable filesystem found"));
544                 return -1;
545         }
546         total /= sizeof(EFI_HANDLE);
547         DBG_PRT((L"found %d filesystems", total));
548
549         dev_tab = (device_t *)alloc(total*sizeof(device_t), EfiLoaderData);
550         if (dev_tab == NULL) {
551                 ERR_PRT((L"failed to allocate handle table"));
552                 return -1;
553         }
554
555         Memset(dev_tab, 0, total*sizeof(device_t));
556
557         /* 
558          * do a 2nd pass to initialize the table now
559          */
560         for(fs = fs_tab; *fs; fs++) {
561                 size = 0;
562
563                 BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
564                 if (size == 0) continue;
565
566                 add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue);
567         }
568         probe_devname_schemes(dev_tab, ndev);
569
570         return 0;
571 }
572
573 static INTN
574 fileops_init(VOID)
575 {
576         UINTN i;
577
578         for (i=0; i < FILEOPS_FD_MAX-1; i++) {
579                 fd_tab[i].next = &fd_tab[i+1];
580         }
581         fd_tab[i].next = NULL;
582         free_fd        = fd_tab;
583
584         return 0;
585 }
586
587 /*
588  * both functions will go away once we go with boottime drivers
589  */
590 static INTN
591 install_filesystems(VOID)
592 {
593         fileops_fs_t **fs;
594
595         for(fs = fs_tab; *fs; fs++) (*fs)->install();
596
597         return 0;
598 }
599
600 static INTN
601 uninstall_filesystems(VOID)
602 {
603         fileops_fs_t **fs;
604
605         for(fs = fs_tab; *fs; fs++) (*fs)->uninstall();
606
607         return 0;
608 }
609
610 INTN
611 init_devices(EFI_HANDLE boot_handle)
612 {
613         /* simulate driver installation */
614         install_filesystems();
615
616         /*
617          * now let's do our part
618          */
619         fileops_init();
620
621         return find_filesystems(boot_handle);
622 }
623
624 INTN
625 close_devices(VOID)
626 {
627         INTN i;
628
629         for(i=0; i < FILEOPS_FD_MAX; i++) {
630                 fops_close(i);
631         }
632         free(dev_tab);
633
634         /*
635          * simulate driver removal
636          */
637         uninstall_filesystems();
638
639         return 0;
640 }
641
642 VOID
643 print_devices(VOID)
644 {
645         UINTN idx;
646         EFI_DEVICE_PATH *dp;
647         CHAR16 *str, *str2;
648
649         for(idx=0; idx< ndev; idx++) {
650                 str = NULL;
651
652                 dp = DevicePathFromHandle(dev_tab[idx].dev);
653                 if (dp) str = DevicePathToStr(dp);
654
655                 str2 = str == NULL ? L"Unknown" : str;
656
657                 Print(L"%8s : %-6s : %s\n", dev_tab[idx].name,
658                                 (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2);
659
660                 if (str) FreePool(str);
661         }
662         Print(L"%d devices available for booting\n", ndev_boot);
663
664         if (boot_dev == NULL) {
665                 Print(L"boot device not detected\n");
666         } else {
667                 Print(L"boot device %s: %s\n", boot_dev->name,
668                                 (boot_dev->fops ? boot_dev->fops->name : L"No file access"));
669         }
670 }