Imported Upstream version 3.10
[debian/elilo] / ia64 / fpswa.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 typedef struct {
33                 UINT32  revision;
34                 UINT32  reserved;
35                 VOID    *fpswa;
36 } fpswa_interface_t;
37
38 INTN
39 query_fpswa(VOID **fpswa)
40 {
41         EFI_HANDLE fpswa_image;
42         UINTN size;
43         EFI_STATUS status;
44         EFI_GUID FpswaProtocol = FPSWA_PROTOCOL;
45
46         DBG_PRT((L"Querying FpswaProtocol"));
47
48         size   = sizeof(EFI_HANDLE);
49
50         status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image);
51         if (EFI_ERROR(status)) {
52                 ERR_PRT((L"boot_params could not locate FPSWA driver", status));
53                 return -1;
54          }
55         status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa);
56         if (EFI_ERROR(status)) {
57                 ERR_PRT((L"boot_params FpswaProtocol not able find the interface"));
58                 return -1;
59         } 
60         VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa,
61                                 ((fpswa_interface_t *)*fpswa)->revision));
62         return 0;
63 }
64
65
66 static INTN
67 do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
68 {
69         EFI_STATUS status;
70         EFI_HANDLE handle;
71         EFI_DEVICE_PATH *dp;
72
73
74         dp = FileDevicePath(dev, fpswa_file);
75         if (dp == NULL) {
76                 ERR_PRT((L"Cannot create FilePath for %s", fpswa_file));
77                 return -1;
78         }
79         status = BS->LoadImage(0, image, dp, NULL, 0, &handle);
80         if (EFI_ERROR(status)) {
81                 VERB_PRT(3, Print(L"..not found\n"));
82                 FreePool(dp);
83                 return -1;
84         }
85         VERB_PRT(3, Print(L"..starting.."));
86
87         status = BS->StartImage(handle, 0, 0);
88         if (EFI_ERROR(status)) {
89                 VERB_PRT(3, Print(L"failed (%r)\n", status));
90                 /* 
91                  * StartImage() automatically unloads if error 
92                  * FPSWA init code will automatically abort if newer revision
93                  * is already installed
94                  */     
95         } else {
96                 VERB_PRT(3, Print(L"..ok\n"));
97         }
98         FreePool(dp);
99
100         return 0;
101 }
102
103 /*
104  * If the caller specifies a fpswa filename, then it used instead of the
105  * defaults.
106  * Return:
107  *      0 : indicates that one fpswa driver was loaded, i.e. an update could be done
108  *      -1: no update was found that would have a more recent version of the driver. This is 
109  *          not a fatal return value.
110  */
111 INTN
112 check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
113 {
114         /*
115          * we must use \\ here as this is given to LoadImage() directly
116          *
117          * The FPSWA driver MUST be called fpswa.efi and the FPSWA document
118          * (see developer.intel.com/design/itanium) stipulates that the 
119          * file must be placed in \EFI\Intel Firmware\ (no mention of which
120          * EFI system partition). So elilo will check on all accessible
121          * Fat32+ partition for the existence of this directory and file.
122          */
123         static CHAR16 *fpswa_filenames[] ={
124                 L"\\efi\\intel firmware\\fpswa.efi",
125 #if 0
126                 L"\\fpswa.efi",
127                 L"\\fw\\fpswa.efi",
128                 L"\\efi\\fpswa.efi",
129                 L"\\efi\\tools\\fpswa.efi",
130                 L"\\fpswa.efi",
131                 L"fpswa.efi",
132 #endif
133         };
134         UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
135         UINTN cookie;
136         CHAR16 devname[FILENAME_MAXLEN];
137         
138         if (fpswa_file) {
139                 INTN r;
140                 devname[0] = CHAR_NULL;
141                 r = fops_split_path(fpswa_file, devname);
142                 if (r == -1) {
143                         ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file));
144                         return -1;
145                 }
146                 if (devname[0] != CHAR_NULL) {
147                         if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) {
148                                 ERR_PRT((L"cannot find device %s for FPSWA driver", devname));
149                                 return -1;
150                         }
151                 }
152                 return do_check_fpswa(image, dev, fpswa_file);
153         }
154
155         cookie = 0;
156         while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) {
157                 for (j = 0; j < count; j++) {
158                         VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j]));
159                         /*
160                          * we need to do all choices to make sure we pickup
161                          * the latest version.
162                          */
163                         do_check_fpswa(image, dev, fpswa_filenames[j]);
164                 }
165         }
166         return -1;
167 }