168 lines
4.5 KiB
C
168 lines
4.5 KiB
C
|
/*
|
||
|
* Copyright (C) 2001-2003 Hewlett-Packard Co.
|
||
|
* Contributed by Stephane Eranian <eranian@hpl.hp.com>
|
||
|
*
|
||
|
* This file is part of the ELILO, the EFI Linux boot loader.
|
||
|
*
|
||
|
* ELILO is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
*
|
||
|
* ELILO is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with ELILO; see the file COPYING. If not, write to the Free
|
||
|
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||
|
* 02111-1307, USA.
|
||
|
*
|
||
|
* Please check out the elilo.txt for complete documentation on how
|
||
|
* to use this program.
|
||
|
*/
|
||
|
|
||
|
#include <efi.h>
|
||
|
#include <efilib.h>
|
||
|
|
||
|
#include "elilo.h"
|
||
|
#include "fileops.h"
|
||
|
|
||
|
typedef struct {
|
||
|
UINT32 revision;
|
||
|
UINT32 reserved;
|
||
|
VOID *fpswa;
|
||
|
} fpswa_interface_t;
|
||
|
|
||
|
INTN
|
||
|
query_fpswa(VOID **fpswa)
|
||
|
{
|
||
|
EFI_HANDLE fpswa_image;
|
||
|
UINTN size;
|
||
|
EFI_STATUS status;
|
||
|
EFI_GUID FpswaProtocol = FPSWA_PROTOCOL;
|
||
|
|
||
|
DBG_PRT((L"Querying FpswaProtocol"));
|
||
|
|
||
|
size = sizeof(EFI_HANDLE);
|
||
|
|
||
|
status = BS->LocateHandle(ByProtocol, &FpswaProtocol, NULL, &size, &fpswa_image);
|
||
|
if (EFI_ERROR(status)) {
|
||
|
ERR_PRT((L"boot_params could not locate FPSWA driver", status));
|
||
|
return -1;
|
||
|
}
|
||
|
status = BS->HandleProtocol(fpswa_image, &FpswaProtocol, fpswa);
|
||
|
if (EFI_ERROR(status)) {
|
||
|
ERR_PRT((L"boot_params FpswaProtocol not able find the interface"));
|
||
|
return -1;
|
||
|
}
|
||
|
VERB_PRT(3, Print(L"FpswaProtocol = 0x%lx revision=%x\n", *fpswa,
|
||
|
((fpswa_interface_t *)*fpswa)->revision));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
static INTN
|
||
|
do_check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
|
||
|
{
|
||
|
EFI_STATUS status;
|
||
|
EFI_HANDLE handle;
|
||
|
EFI_DEVICE_PATH *dp;
|
||
|
|
||
|
|
||
|
dp = FileDevicePath(dev, fpswa_file);
|
||
|
if (dp == NULL) {
|
||
|
ERR_PRT((L"Cannot create FilePath for %s", fpswa_file));
|
||
|
return -1;
|
||
|
}
|
||
|
status = BS->LoadImage(0, image, dp, NULL, 0, &handle);
|
||
|
if (EFI_ERROR(status)) {
|
||
|
VERB_PRT(3, Print(L"..not found\n"));
|
||
|
FreePool(dp);
|
||
|
return -1;
|
||
|
}
|
||
|
VERB_PRT(3, Print(L"..starting.."));
|
||
|
|
||
|
status = BS->StartImage(handle, 0, 0);
|
||
|
if (EFI_ERROR(status)) {
|
||
|
VERB_PRT(3, Print(L"failed (%r)\n", status));
|
||
|
/*
|
||
|
* StartImage() automatically unloads if error
|
||
|
* FPSWA init code will automatically abort if newer revision
|
||
|
* is already installed
|
||
|
*/
|
||
|
} else {
|
||
|
VERB_PRT(3, Print(L"..ok\n"));
|
||
|
}
|
||
|
FreePool(dp);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the caller specifies a fpswa filename, then it used instead of the
|
||
|
* defaults.
|
||
|
* Return:
|
||
|
* 0 : indicates that one fpswa driver was loaded, i.e. an update could be done
|
||
|
* -1: no update was found that would have a more recent version of the driver. This is
|
||
|
* not a fatal return value.
|
||
|
*/
|
||
|
INTN
|
||
|
check_fpswa(EFI_HANDLE image, EFI_HANDLE dev, CHAR16 *fpswa_file)
|
||
|
{
|
||
|
/*
|
||
|
* we must use \\ here as this is given to LoadImage() directly
|
||
|
*
|
||
|
* The FPSWA driver MUST be called fpswa.efi and the FPSWA document
|
||
|
* (see developer.intel.com/design/itanium) stipulates that the
|
||
|
* file must be placed in \EFI\Intel Firmware\ (no mention of which
|
||
|
* EFI system partition). So elilo will check on all accessible
|
||
|
* Fat32+ partition for the existence of this directory and file.
|
||
|
*/
|
||
|
static CHAR16 *fpswa_filenames[] ={
|
||
|
L"\\efi\\intel firmware\\fpswa.efi",
|
||
|
#if 0
|
||
|
L"\\fpswa.efi",
|
||
|
L"\\fw\\fpswa.efi",
|
||
|
L"\\efi\\fpswa.efi",
|
||
|
L"\\efi\\tools\\fpswa.efi",
|
||
|
L"\\fpswa.efi",
|
||
|
L"fpswa.efi",
|
||
|
#endif
|
||
|
};
|
||
|
UINTN j, count = sizeof(fpswa_filenames)/sizeof(CHAR16 *);
|
||
|
INTN cookie;
|
||
|
CHAR16 devname[FILENAME_MAXLEN];
|
||
|
|
||
|
if (fpswa_file) {
|
||
|
INTN r;
|
||
|
devname[0] = CHAR_NULL;
|
||
|
r = fops_split_path(fpswa_file, devname);
|
||
|
if (r == -1) {
|
||
|
ERR_PRT((L"FPSWA driver filename too long %s", fpswa_file));
|
||
|
return -1;
|
||
|
}
|
||
|
if (devname[0] != CHAR_NULL) {
|
||
|
if (fops_get_device_handle(devname, &dev) != EFI_SUCCESS) {
|
||
|
ERR_PRT((L"cannot find device %s for FPSWA driver", devname));
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
return do_check_fpswa(image, dev, fpswa_file);
|
||
|
}
|
||
|
|
||
|
cookie = 0;
|
||
|
while (fops_get_next_device(cookie, L"vfat", FILENAME_MAXLEN, &cookie, devname, &dev) == EFI_SUCCESS) {
|
||
|
for (j = 0; j < count; j++) {
|
||
|
VERB_PRT(3, Print(L"Trying FPSWA driver %s:%s..", devname, fpswa_filenames[j]));
|
||
|
/*
|
||
|
* we need to do all choices to make sure we pickup
|
||
|
* the latest version.
|
||
|
*/
|
||
|
do_check_fpswa(image, dev, fpswa_filenames[j]);
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|