2 * Copyright (C) 2001-2003 Hewlett-Packard Co.
3 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
5 * This file is part of the ELILO, the EFI Linux boot loader.
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)
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.
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
22 * Please check out the elilo.txt for complete documentation on how
23 * to use this program.
36 #include "glue_localfs.h"
39 #include "glue_netfs.h"
43 #include "glue_ext2fs.h"
47 * table of device naming schemes.
48 * we will probe each one in sequential order and stop at first match.
50 extern devname_scheme_t simple_devname_scheme;
52 static devname_scheme_t *devname_scheme_tab[]={
53 &simple_devname_scheme,
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
65 typedef EFI_STATUS (fops_fixups_t)(EFI_HANDLE dev, device_t *d);
68 * List of filesystem we currently support
72 static fileops_fs_t *fs_tab[]={
85 static device_t *dev_tab;
86 static UINTN ndev, ndev_boot;
87 static device_t *boot_dev;
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 */
95 #define FILEOPS_FD_MAX 16
97 static fdesc_t fd_tab[FILEOPS_FD_MAX];
98 static fdesc_t *free_fd;
100 static devname_scheme_t *current_devname_scheme;
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))
111 if (free_fd == NULL) {
112 ERR_PRT((L"out of file descriptor"));
115 free_fd = free_fd->next;
124 ERR_PRT((L"invalid fd"));
126 fd->fops = NULL; /* mark as invalid */
132 glue_filesystem(EFI_GUID *proto, EFI_HANDLE dev, fops_fs_glue_t glue)
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 */
143 fops = (fileops_t *)alloc(sizeof(*fops), EfiLoaderData);
145 ERR_PRT((L"failed to allocate fileops"));
146 return NULL; /* XXX uninstall protocol */
148 Memset(fops, 0, sizeof(*fops));
152 /* initialize private interface now */
159 fops_split_path(CHAR16 *path, CHAR16 *dev)
162 UINTN len = FILEOPS_DEVNAME_MAXLEN;
163 # define CHAR_COLON L':'
165 p = StrChr(path, CHAR_COLON);
170 /* copy device part of the name */
171 for (d = dev ; path != p ;) {
172 if (--len == 0) return -1; /* too long */
180 find_device_byname(CHAR16 *dev)
183 for(i=0; i < ndev; i++) {
184 if (!StrCmp(dev, dev_tab[i].name)) return dev_tab+i;
191 * This function is used to walk through the device list and get names.
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
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
207 fops_get_next_device(UINTN pidx, CHAR16 *type, UINTN maxlen, UINTN *idx, CHAR16 *name, EFI_HANDLE *dev)
211 if (name == NULL || idx == NULL) return EFI_INVALID_PARAMETER;
213 for(i=pidx; i < ndev; i++) {
214 if (type == NULL || !StrCmp(dev_tab[i].fops->name, type)) goto found;
216 return EFI_NOT_FOUND;
218 if (StrLen(dev_tab[i].name) >= maxlen) {
219 *idx = pidx; /* will restart from same place! */
220 return EFI_BUFFER_TOO_SMALL;
222 StrCpy(name, dev_tab[i].name);
224 if (dev) *dev = dev_tab[i].dev;
230 fops_get_device_handle(CHAR16 *name, EFI_HANDLE *dev)
234 if (name == NULL || dev == NULL) return EFI_INVALID_PARAMETER;
236 for(i=0; i < ndev; i++) {
237 if (!StrCmp(dev_tab[i].name, name)) goto found;
239 return EFI_NOT_FOUND;
241 *dev = dev_tab[i].dev;
248 fops_open(CHAR16 *fullname, fops_fd_t *fd)
254 CHAR16 dev_name[FILEOPS_DEVNAME_MAXLEN];
258 if (fd == NULL || fullname == NULL || *fullname == CHAR_NULL || fops_split_path(fullname, dev_name) == -1)
259 return EFI_INVALID_PARAMETER;
261 DBG_PRT((L"fops_open(%s), dev:%s:", fullname ? fullname : L"(NULL)", dev_name));
264 if (dev_name[0] == CHAR_NULL) {
265 if (boot_dev == NULL) return EFI_INVALID_PARAMETER;
266 fops = boot_dev->fops;
268 if ((dev=find_device_byname(dev_name)) == NULL) return EFI_INVALID_PARAMETER;
270 name += StrLen(dev_name)+1;
275 if (fops == NULL) return EFI_INVALID_PARAMETER;
277 if ((f=fd_alloc()) == NULL) return EFI_OUT_OF_RESOURCES;
279 DBG_PRT((L"dev:%s: fullname:%s: name:%s: f=%d", dev_name, fullname, name, f - fd_tab));
281 status = fops->open(fops->intf, name, &f->fh);
282 if (EFI_ERROR(status)) goto error;
295 fops_read(fops_fd_t fd, VOID *buf, UINTN *size)
299 if (buf == NULL || FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
303 return f->fops->read(f->fops->intf, f->fh, buf, size);
307 fops_close(fops_fd_t fd)
312 if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
316 status = f->fops->close(f->fops->intf, f->fh);
324 fops_infosize(fops_fd_t fd, UINT64 *size)
328 if (FDESC_INVALID_FD(fd) || size == NULL) return EFI_INVALID_PARAMETER;
332 return f->fops->infosize(f->fops->intf, f->fh, size);
336 fops_seek(fops_fd_t fd, UINT64 newpos)
340 if (FDESC_INVALID_FD(fd)) return EFI_INVALID_PARAMETER;
344 return f->fops->seek(f->fops->intf, f->fh, newpos);
348 fops_setdefaults(CHAR16 *config, CHAR16 *kname, UINTN maxlen, CHAR16 *devpath)
350 #define FILEOPS_DEFAULT_KERNEL L"vmlinux"
351 #define FILEOPS_DEFAULT_CONFIG L"elilo.conf"
353 if (config == NULL || kname == NULL) return EFI_INVALID_PARAMETER;
355 if (boot_dev == NULL || boot_dev->fops == NULL) {
356 if (boot_dev == NULL)
357 Print(L"Warning boot device not recognized\n");
359 Print(L"Unknown filesystem on boot device\n");
361 Print(L"Using builtin defaults for kernel and config file\n");
363 StrnCpy(config, FILEOPS_DEFAULT_CONFIG, maxlen-1);
364 StrnCpy(kname, FILEOPS_DEFAULT_KERNEL, maxlen-1);
366 return EFI_UNSUPPORTED;
369 return boot_dev->fops->setdefaults(boot_dev->fops->intf, config, kname, maxlen, devpath);
373 fops_getdefault_path(CHAR16 *path, UINTN maxlen)
375 if (path == NULL || maxlen == 0) return EFI_INVALID_PARAMETER;
378 * if underlying filesystem implements the call, then we call
379 * otherwise we return an empty string
381 if (boot_dev->fops->getdefault_path)
382 return boot_dev->fops->getdefault_path(path, maxlen);
390 fops_bootdev_name(VOID)
392 return boot_dev ? boot_dev->name : L"not supported";
396 add_dev_tab(EFI_GUID *proto, EFI_HANDLE boot_handle, UINTN size, fops_fs_glue_t glue)
403 if (size == 0) return 0;
405 tab = (EFI_HANDLE *)alloc(size, EfiLoaderData);
407 ERR_PRT((L"failed to allocate handle table"));
411 Memset(tab, 0, size);
414 * get the actual device handles now
416 status = BS->LocateHandle(ByProtocol, proto, NULL, &size, tab);
417 if (status != EFI_SUCCESS) {
418 ERR_PRT((L"failed to get handles for proto %g size=%d: %r", proto, size, status));
422 size /= sizeof(EFI_HANDLE);
424 for(i=0; i < size; i++) {
425 dev_tab[idx].dev = tab[i];
426 dev_tab[idx].fops = glue_filesystem(proto, tab[i], glue);
428 if (tab[i] == boot_handle) boot_dev = dev_tab+idx;
430 /* count the ones we recognized */
431 if (dev_tab[idx].fops) ndev_boot++;
433 /* assign a generic name for now */
434 dev_tab[idx].name[0] = L'd';
435 dev_tab[idx].name[1] = L'e';
436 dev_tab[idx].name[2] = L'v';
437 dev_tab[idx].name[3] = L'0' + idx/100;
438 dev_tab[idx].name[4] = L'0' + (idx%100)/10;
439 dev_tab[idx].name[5] = L'0' + (idx%100) % 10;
440 dev_tab[idx].name[6] = CHAR_NULL;
443 if (elilo_opt.debug) {
448 dp = DevicePathFromHandle(dev_tab[idx].dev);
449 if (dp) str = DevicePathToStr(dp);
451 str2 = str == NULL ? L"Unknown" : str;
453 DBG_PRT((L"%s : %-8s : %s\n", dev_tab[idx].name,
454 (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2));
456 if (str) FreePool(str);
464 /* remember actual number of bootable devices */
471 probe_devname_schemes(device_t *dev_tab, INTN ndev)
473 devname_scheme_t **p;
475 for (p = devname_scheme_tab; *p ; p++) {
476 if ((*p)->install_scheme(dev_tab, ndev) == 0) goto found;
478 ERR_PRT((L"No devname schemes worked, using builtin\n"));
481 VERB_PRT(3, Print(L"devname scheme: %s\n", (*p)->name));
482 current_devname_scheme = *p;
487 find_filesystems(EFI_HANDLE boot_handle)
489 UINTN size, total = 0;
493 * 1st pass, figure out how big a table we need
495 for(fs = fs_tab; *fs; fs++) {
497 BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
501 ERR_PRT((L"No useable filesystem found"));
504 total /= sizeof(EFI_HANDLE);
505 DBG_PRT((L"found %d filesystems", total));
507 dev_tab = (device_t *)alloc(total*sizeof(device_t), EfiLoaderData);
508 if (dev_tab == NULL) {
509 ERR_PRT((L"failed to allocate handle table"));
513 Memset(dev_tab, 0, total*sizeof(device_t));
516 * do a 2nd pass to initialize the table now
518 for(fs = fs_tab; *fs; fs++) {
521 BS->LocateHandle(ByProtocol, &(*fs)->proto, NULL, &size, NULL);
522 if (size == 0) continue;
524 add_dev_tab(&(*fs)->proto, boot_handle, size, (*fs)->glue);
526 probe_devname_schemes(dev_tab, ndev);
536 for (i=0; i < FILEOPS_FD_MAX-1; i++) {
537 fd_tab[i].next = &fd_tab[i+1];
539 fd_tab[i].next = NULL;
546 * both functions will go away once we go with boottime drivers
549 install_filesystems(VOID)
553 for(fs = fs_tab; *fs; fs++) (*fs)->install();
559 uninstall_filesystems(VOID)
563 for(fs = fs_tab; *fs; fs++) (*fs)->uninstall();
569 init_devices(EFI_HANDLE boot_handle)
571 /* simulate driver installation */
572 install_filesystems();
575 * now let's do our part
579 return find_filesystems(boot_handle);
587 for(i=0; i < FILEOPS_FD_MAX; i++) {
593 * simulate driver removal
595 uninstall_filesystems();
607 for(idx=0; idx< ndev; idx++) {
610 dp = DevicePathFromHandle(dev_tab[idx].dev);
611 if (dp) str = DevicePathToStr(dp);
613 str2 = str == NULL ? L"Unknown" : str;
615 Print(L"%8s : %-6s : %s\n", dev_tab[idx].name,
616 (dev_tab[idx].fops ? dev_tab[idx].fops->name: L"N/A"), str2);
618 if (str) FreePool(str);
620 Print(L"%d devices available for booting\n", ndev_boot);
622 if (boot_dev == NULL) {
623 Print(L"boot device not detected\n");
625 Print(L"boot device %s: %s\n", boot_dev->name,
626 (boot_dev->fops ? boot_dev->fops->name : L"No file access"));