fe1333fee764160bdb28f61b43aaef29087325b0
[debian/elilo] / fs / localfs.c
1 /*
2  *  Copyright (C) 2001-2003 Hewlett-Packard Co.
3  *      Contributed by Stephane Eranian <eranian@hpl.hp.com>
4  *  Copyright (C) 2006-2009 Intel Corporation
5  *      Contributed by Fenghua Yu <fenghua.yu@intel.com>
6  *      Contributed by Bibo Mao <bibo.mao@intel.com>
7  *      Contributed by Chandramouli Narayanan <mouli@linux.intel.com>
8  *
9  * This file is part of the ELILO, the EFI Linux boot loader.
10  *
11  *  ELILO is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2, or (at your option)
14  *  any later version.
15  *
16  *  ELILO is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with ELILO; see the file COPYING.  If not, write to the Free
23  *  Software Foundation, 59 Temple Place - Suite 330, Boston, MA
24  *  02111-1307, USA.
25  *
26  * Please check out the elilo.txt for complete documentation on how
27  * to use this program.
28  */
29
30 #include <efi.h>
31 #include <efilib.h>
32
33 #include "elilo.h"
34 #include "fs/localfs.h"
35
36 /*
37  * LocalFS is just a shim layer on top of the 
38  * FileSystem Protocol which gives access to FAT32,16,12
39  */
40 #define FS_NAME L"vfat"
41
42
43 typedef struct {
44         EFI_HANDLE      dev;            /* device we're attached to */
45         EFI_FILE_HANDLE volume;         /* root of volume */
46 } localfs_priv_state_t;
47
48 #define LOCALFS_F2FD(f)         ((UINTN)(f))
49 #define LOCALFS_FD2F(fd)        ((EFI_FILE_HANDLE)(fd))
50
51 typedef union {
52         localfs_interface_t     pub_intf;
53         struct {
54                 localfs_interface_t     pub_intf;
55                 localfs_priv_state_t    priv_data;
56         } localfs_priv;
57 } localfs_t;
58
59 #define FS_PRIVATE(n)   (&(((localfs_t *)n)->localfs_priv.priv_data))
60
61
62 static EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL;
63
64 /*
65  * let's be clean here
66  */
67 typedef union {
68         EFI_HANDLE dev;
69         localfs_t  *intf;
70 } dev_tab_t;
71
72 static dev_tab_t *dev_tab;      /* holds all devices we found */
73 static UINTN ndev;              /* how many entries in dev_tab */
74
75 static EFI_STATUS
76 localfs_name(localfs_interface_t *this, CHAR16 *name, UINTN maxlen)
77 {
78         if (name == NULL || maxlen < 1) return EFI_INVALID_PARAMETER;
79
80         StrnCpy(name, FS_NAME, maxlen-1);
81
82         name[maxlen-1] = CHAR_NULL;
83
84         return EFI_SUCCESS;
85 }
86
87
88 static EFI_STATUS
89 localfs_open(localfs_interface_t *this, CHAR16 *name, UINTN *fd)
90 {
91         localfs_priv_state_t *lfs;
92         EFI_STATUS              status;
93         EFI_FILE_HANDLE         fh;
94
95         if (this == NULL || name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;
96
97         lfs = FS_PRIVATE(this);
98
99         DBG_PRT((L"localfs_open on %s\n", name));
100
101         status = uefi_call_wrapper(lfs->volume->Open, 5, lfs->volume, &fh, name, EFI_FILE_MODE_READ, 0);
102         if (status == EFI_SUCCESS) {
103                 *fd = LOCALFS_F2FD(fh);
104         } 
105         return status;
106 }
107
108 static EFI_STATUS
109 localfs_read(localfs_interface_t *this, UINTN fd, VOID *buf, UINTN *size)
110 {
111         localfs_priv_state_t *lfs;
112
113         if (this == NULL || fd == 0 || buf == NULL || size == NULL) return EFI_INVALID_PARAMETER;
114
115         lfs = FS_PRIVATE(this);
116
117         return uefi_call_wrapper(lfs->volume->Read, 3, LOCALFS_FD2F(fd), size, buf);
118 }
119
120 static EFI_STATUS
121 localfs_close(localfs_interface_t *this, UINTN fd)
122 {
123         localfs_priv_state_t *lfs;
124
125         if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
126
127         lfs = FS_PRIVATE(this);
128
129         return uefi_call_wrapper(lfs->volume->Close, 1, LOCALFS_FD2F(fd));
130 }
131
132 static EFI_STATUS
133 localfs_infosize(localfs_interface_t *this, UINTN fd, UINT64 *sz)
134 {
135         localfs_priv_state_t *lfs;
136         EFI_FILE_INFO        *info;
137
138         if (this == NULL || fd == 0 || sz == NULL) return EFI_INVALID_PARAMETER;
139
140         lfs = FS_PRIVATE(this);
141
142         info = LibFileInfo(LOCALFS_FD2F(fd));
143         if (info == NULL) return EFI_UNSUPPORTED;
144
145         *sz = info->FileSize;
146
147         uefi_call_wrapper(BS->FreePool, 1, info);
148
149         return EFI_SUCCESS;
150 }
151
152 static EFI_STATUS
153 localfs_seek(localfs_interface_t *this, UINTN fd, UINT64 newpos)
154 {
155         localfs_priv_state_t *lfs;
156
157         if (this == NULL || fd == 0) return EFI_INVALID_PARAMETER;
158
159         lfs = FS_PRIVATE(this);
160
161         return uefi_call_wrapper(lfs->volume->SetPosition, 2, LOCALFS_FD2F(fd), newpos);
162 }
163
164 static VOID
165 localfs_init_state(localfs_t *localfs, EFI_HANDLE dev, EFI_FILE_HANDLE volume)
166 {
167         localfs_priv_state_t *lfs = FS_PRIVATE(localfs);
168
169         /* need to do some init here on localfs_intf */
170         Memset(localfs, 0, sizeof(*localfs));
171
172         localfs->pub_intf.localfs_name        = localfs_name;
173         localfs->pub_intf.localfs_open        = localfs_open;
174         localfs->pub_intf.localfs_read        = localfs_read;
175         localfs->pub_intf.localfs_close       = localfs_close;
176         localfs->pub_intf.localfs_infosize    = localfs_infosize;
177         localfs->pub_intf.localfs_seek        = localfs_seek;
178
179         lfs->dev    = dev;
180         lfs->volume = volume;
181 }
182
183 static EFI_STATUS
184 localfs_install_one(EFI_HANDLE dev, VOID **intf)
185 {
186
187         EFI_STATUS              status;
188         localfs_t               *localfs;
189         EFI_FILE_IO_INTERFACE   *volume;
190         EFI_FILE_HANDLE         volume_fh;
191
192         status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &LocalFsProtocol, (VOID **)&localfs);
193         if (status == EFI_SUCCESS) {
194                 ERR_PRT((L"Warning: found existing %s protocol on device", FS_NAME));
195                 goto found;
196         }
197         
198         status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &FileSystemProtocol, (VOID **)&volume);
199         if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;
200
201         status = uefi_call_wrapper(volume->OpenVolume, 2, volume, &volume_fh);
202         if (EFI_ERROR(status)) {
203                 ERR_PRT((L"cannot open volume"));
204                 return status;
205         }
206
207         localfs = (localfs_t *)alloc(sizeof(*localfs), EfiLoaderData);
208         if (localfs == NULL) {
209                 ERR_PRT((L"failed to allocate %s", FS_NAME));
210                 return EFI_OUT_OF_RESOURCES;
211         }
212         localfs_init_state(localfs, dev, volume_fh);
213
214         status = LibInstallProtocolInterfaces(&dev, &LocalFsProtocol, localfs, NULL);
215         if (EFI_ERROR(status)) {
216                 ERR_PRT((L"Cannot install %s protocol: %r", FS_NAME, status));
217                 free(localfs);
218                 return status;
219         }
220 found:
221         if (intf) *intf = (VOID *)localfs;
222
223         VERB_PRT(3,
224                 { EFI_DEVICE_PATH *dp; CHAR16 *str;
225                   dp  = DevicePathFromHandle(dev);
226                   str = DevicePathToStr(dp);
227                   Print(L"attached %s to %s\n", FS_NAME, str);
228                   uefi_call_wrapper(BS->FreePool, 1, str);
229                 });
230
231         return EFI_SUCCESS;
232 }
233         
234 EFI_STATUS
235 localfs_install(VOID)
236 {
237         UINTN size = 0;
238         UINTN i;
239         EFI_STATUS status;
240         VOID *intf;
241
242         uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
243         if (size == 0) return EFI_UNSUPPORTED; /* no device found, oh well */
244
245         DBG_PRT((L"size=%d", size));
246
247         dev_tab = (dev_tab_t *)alloc(size, EfiLoaderData);
248         if (dev_tab == NULL) {
249                 ERR_PRT((L"failed to allocate handle table"));
250                 return EFI_OUT_OF_RESOURCES;
251         }
252         status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
253         if (status != EFI_SUCCESS) {
254                 ERR_PRT((L"failed to get handles: %r", status));
255                 free(dev_tab);
256                 return status;
257         }
258         ndev = size / sizeof(EFI_HANDLE);
259
260         for(i=0; i < ndev; i++) {
261                 intf = NULL;
262                 localfs_install_one(dev_tab[i].dev, &intf);
263                 /* override device handle with interface pointer */
264                 dev_tab[i].intf = intf;
265         }
266
267         return EFI_SUCCESS;
268 }
269         
270 EFI_STATUS
271 localfs_uninstall(VOID)
272 {
273         
274         localfs_priv_state_t *lfs;
275         EFI_STATUS status;
276         UINTN i;
277
278         for(i=0; i < ndev; i++) {
279                 if (dev_tab[i].intf == NULL) continue;
280                 lfs = FS_PRIVATE(dev_tab[i].intf);
281                 status = uefi_call_wrapper(BS->UninstallProtocolInterface, 3, lfs->dev, &LocalFsProtocol, dev_tab[i].intf);
282                 if (EFI_ERROR(status)) {
283                         ERR_PRT((L"Uninstall %s error: %r", FS_NAME, status));
284                         continue;
285                 }
286                 VERB_PRT(3,
287                         { EFI_DEVICE_PATH *dp; CHAR16 *str;
288                         dp  = DevicePathFromHandle(lfs->dev);
289                         str = DevicePathToStr(dp);
290                         Print(L"uninstalled %s on %s\n", FS_NAME, str);
291                         uefi_call_wrapper(BS->FreePool, 1, str);
292                         });
293                 free(dev_tab[i].intf);
294         }
295         if (dev_tab) free(dev_tab);
296
297         return EFI_SUCCESS;
298 }
299
300