/* Read an EFI shell variable */ const char * grub_env_get(const char *var) { EFI_STATUS Status; CHAR16 Var[64], Val[128]; UINTN ValSize = sizeof(Val); static char val[128] = { 0 }; Status = Utf8ToUtf16NoAlloc((CHAR8 *) var, Var, ARRAYSIZE(Var)); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert variable name to UTF-16"); return NULL; } Status = RT->GetVariable(Var, &ShellVariable, NULL, &ValSize, Val); if (EFI_ERROR(Status)) return NULL; Status = Utf16ToUtf8NoAlloc(Val, val, sizeof(val)); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert value '%s' to UTF-8", Val); return NULL; } return val; }
/** * Install the EFI simple file system protocol * If successful this call instantiates a new FS#: drive, that is made * available on the next 'map -r'. Note that all this call does is add * the FS protocol. OpenVolume won't be called until a process tries * to access a file or the root directory on the volume. */ EFI_STATUS FSInstall(EFI_FS *This, EFI_HANDLE ControllerHandle) { EFI_STATUS Status; /* Check if it's a filesystem we can handle */ if (!GrubFSProbe(This)) return EFI_UNSUPPORTED; PrintInfo(L"FSInstall: %s\n", This->DevicePathString); /* Initialize the root handle */ Status = GrubCreateFile(&This->RootFile, This); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not create root file"); return Status; } /* Setup the EFI part */ This->RootFile->EfiFile.Revision = EFI_FILE_HANDLE_REVISION; This->RootFile->EfiFile.Open = FileOpen; This->RootFile->EfiFile.Close = FileClose; This->RootFile->EfiFile.Delete = FileDelete; This->RootFile->EfiFile.Read = FileRead; This->RootFile->EfiFile.Write = FileWrite; This->RootFile->EfiFile.GetPosition = FileGetPosition; This->RootFile->EfiFile.SetPosition = FileSetPosition; This->RootFile->EfiFile.GetInfo = FileGetInfo; This->RootFile->EfiFile.SetInfo = FileSetInfo; This->RootFile->EfiFile.Flush = FileFlush; /* Setup the other attributes */ This->RootFile->path = "/"; This->RootFile->basename = &This->RootFile->path[1]; This->RootFile->IsDir = TRUE; /* Install the simple file system protocol. */ Status = LibInstallProtocolInterfaces(&ControllerHandle, &FileSystemProtocol, &This->FileIoInterface, NULL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not install simple file system protocol"); return Status; } return EFI_SUCCESS; }
static EFI_STATUS EFIAPI FSBindingStop(EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE ControllerHandle, UINTN NumberOfChildren, EFI_HANDLE *ChildHandleBuffer) { EFI_STATUS Status; EFI_FS *Instance; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileIoInterface; PrintDebug(L"FSBindingStop\n"); /* Get a pointer back to our FS instance through its installed protocol */ Status = BS->OpenProtocol(ControllerHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **) &FileIoInterface, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not locate our instance"); return Status; } Instance = _CR(FileIoInterface, EFI_FS, FileIoInterface); FSUninstall(Instance, ControllerHandle); Status = GrubDeviceExit(Instance); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not destroy grub device"); } BS->CloseProtocol(ControllerHandle, &gEfiDiskIo2ProtocolGuid, This->DriverBindingHandle, ControllerHandle); BS->CloseProtocol(ControllerHandle, &gEfiDiskIoProtocolGuid, This->DriverBindingHandle, ControllerHandle); FreeFsInstance(Instance); return EFI_SUCCESS; }
/** * Get EFI file name (for debugging) * * @v file EFI file * @ret Name Name */ static const CHAR16 * FileName(EFI_GRUB_FILE *File) { EFI_STATUS Status; static CHAR16 Path[MAX_PATH]; Status = Utf8ToUtf16NoAlloc(File->path, Path, sizeof(Path)); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert filename to UTF16"); return NULL; } return Path; }
/** * Uninstall EFI driver * * @v ImageHandle Handle identifying the loaded image * @ret Status EFI status code to return on exit */ EFI_STATUS EFIAPI FSDriverUninstall(EFI_HANDLE ImageHandle) { EFI_STATUS Status; UINTN NumHandles; EFI_HANDLE *Handles; UINTN i; /* Enumerate all handles */ Status = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &NumHandles, &Handles); /* Disconnect controllers linked to our driver. This action will trigger a call to BindingStop */ if (Status == EFI_SUCCESS) { for (i=0; i<NumHandles; i++) { /* Make sure to filter on DriverBindingHandle, else EVERYTHING gets disconnected! */ Status = BS->DisconnectController(Handles[i], FSDriverBinding.DriverBindingHandle, NULL); if (Status == EFI_SUCCESS) PrintDebug(L"DisconnectController[%d]\n", i); } } else { PrintStatusError(Status, L"Unable to enumerate handles"); } if (Handles != NULL) { BS->FreePool(Handles); Handles = NULL; } /* Now that all controllers are disconnected, we can safely remove our protocols */ BS->UninstallMultipleProtocolInterfaces(ImageHandle, &gEfiDriverBindingProtocolGuid, &FSDriverBinding, &gEfiComponentNameProtocolGuid, &FSComponentName, &gEfiComponentName2ProtocolGuid, &FSComponentName2, NULL); /* Release the relevant GRUB fs module(s) */ GrubDriverExit(); /* Uninstall our mutex (we're the only instance that can run this code) */ BS->UninstallMultipleProtocolInterfaces(MutexHandle, MutexGUID, &MutexProtocol, NULL); PrintDebug(L"FS driver uninstalled.\n"); return EFI_SUCCESS; }
/* GRUB uses a callback for each directory entry, whereas EFI uses repeated * firmware generated calls to FileReadDir() to get the info for each entry, * so we have to reconcile the twos. For now, we'll re-issue a call to GRUB * dir(), and run through all the entries (to find the one we * are interested in) multiple times. Maybe later we'll try to optimize this * by building a one-off chained list of entries that we can parse... */ static INT32 DirHook(const CHAR8 *name, const GRUB_DIRHOOK_INFO *DirInfo, VOID *Data) { EFI_STATUS Status; EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data; INT64 *Index = (INT64 *) &Info->FileSize; CHAR8 *filename = (CHAR8 *) Info->PhysicalSize; EFI_TIME Time = { 1970, 01, 01, 00, 00, 00, 0, 0, 0, 0, 0}; // Eliminate '.' or '..' if ((name[0] == '.') && ((name[1] == 0) || ((name[1] == '.') && (name[2] == 0)))) return 0; /* Ignore any entry that doesn't match our index */ if ((*Index)-- != 0) return 0; strcpya(filename, name); Status = Utf8ToUtf16NoAlloc(filename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO))); if (EFI_ERROR(Status)) { if (Status != EFI_BUFFER_TOO_SMALL) PrintStatusError(Status, L"Could not convert directory entry to UTF-8"); return (INT32) Status; } /* The Info struct size already accounts for the extra NUL */ Info->Size = sizeof(*Info) + StrLen(Info->FileName) * sizeof(CHAR16); // Oh, and of course GRUB uses a 32 bit signed mtime value (seriously, wtf guys?!?) if (DirInfo->MtimeSet) GrubTimeToEfiTime(DirInfo->Mtime, &Time); CopyMem(&Info->CreateTime, &Time, sizeof(Time)); CopyMem(&Info->LastAccessTime, &Time, sizeof(Time)); CopyMem(&Info->ModificationTime, &Time, sizeof(Time)); Info->Attribute = EFI_FILE_READ_ONLY; if (DirInfo->Dir) Info->Attribute |= EFI_FILE_DIRECTORY; return 0; }
/** * Open file * * @v This File handle * @ret new New file handle * @v Name File name * @v Mode File mode * @v Attributes File attributes (for newly-created files) * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileOpen(EFI_FILE_HANDLE This, EFI_FILE_HANDLE *New, CHAR16 *Name, UINT64 Mode, UINT64 Attributes) { EFI_STATUS Status; EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); EFI_GRUB_FILE *NewFile; // TODO: Use dynamic buffers? char path[MAX_PATH], clean_path[MAX_PATH], *dirname; INTN i, len; BOOLEAN AbsolutePath = (*Name == L'\\'); PrintInfo(L"Open(%llx%s, \"%s\")\n", (UINT64) This, IS_ROOT(File)?L" <ROOT>":L"", Name); /* Fail unless opening read-only */ if (Mode != EFI_FILE_MODE_READ) { PrintWarning(L"File '%s' can only be opened in read-only mode\n", Name); return EFI_WRITE_PROTECTED; } /* Additional failures */ if ((StrCmp(Name, L"..") == 0) && IS_ROOT(File)) { PrintInfo(L"Trying to open <ROOT>'s parent\n"); return EFI_NOT_FOUND; } /* See if we're trying to reopen current (which the EFI Shell insists on doing) */ if ((*Name == 0) || (StrCmp(Name, L".") == 0)) { PrintInfo(L" Reopening %s\n", IS_ROOT(File)?L"<ROOT>":FileName(File)); File->RefCount++; *New = This; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } /* If we have an absolute path, don't bother completing with the parent */ if (AbsolutePath) { len = 0; } else { strcpya(path, File->path); len = strlena(path); /* Add delimiter if needed */ if ((len == 0) || (path[len-1] != '/')) path[len++] = '/'; } /* Copy the rest of the path (converted to UTF-8) */ Status = Utf16ToUtf8NoAlloc(Name, &path[len], sizeof(path) - len); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not convert path to UTF-8"); return Status; } /* Convert the delimiters */ for (i = strlena(path) - 1 ; i >= len; i--) { if (path[i] == '\\') path[i] = '/'; } /* We only want to handle with absolute paths */ clean_path[0] = '/'; /* Find out if we're dealing with root by removing the junk */ CopyPathRelative(&clean_path[1], path, MAX_PATH - 1); if (clean_path[1] == 0) { /* We're dealing with the root */ PrintInfo(L" Reopening <ROOT>\n"); *New = &File->FileSystem->RootFile->EfiFile; /* Must make sure that DirIndex is reset too (NB: no concurrent access!) */ File->FileSystem->RootFile->DirIndex = 0; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; } // TODO: eventually we should seek for already opened files and increase RefCount */ /* Allocate and initialise an instance of a file */ Status = GrubCreateFile(&NewFile, File->FileSystem); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not instantiate file"); return Status; } NewFile->path = AllocatePool(strlena(clean_path)+1); if (NewFile->path == NULL) { GrubDestroyFile(NewFile); PrintError(L"Could not instantiate path\n"); return EFI_OUT_OF_RESOURCES; } strcpya(NewFile->path, clean_path); /* Isolate the basename and dirname */ // TODO: would be nicer to have those if path.c for (i = strlena(clean_path) - 1; i >= 0; i--) { if (clean_path[i] == '/') { clean_path[i] = 0; break; } } dirname = (i <= 0) ? "/" : clean_path; NewFile->basename = &NewFile->path[i+1]; /* Find if we're working with a directory and fill the grub timestamp */ Status = GrubDir(NewFile, dirname, InfoHook, (VOID *) NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not get file attributes for '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } /* Finally we can call on GRUB open() if it's a regular file */ if (!NewFile->IsDir) { Status = GrubOpen(NewFile); if (EFI_ERROR(Status)) { if (Status != EFI_NOT_FOUND) PrintStatusError(Status, L"Could not open file '%s'", Name); FreePool(NewFile->path); GrubDestroyFile(NewFile); return Status; } } NewFile->RefCount++; *New = &NewFile->EfiFile; PrintInfo(L" RET: %llx\n", (UINT64) *New); return EFI_SUCCESS; }
/** * Get file information * * @v This File handle * @v Type Type of information * @v Len Buffer size * @v Data Buffer * @ret Status EFI status code */ static EFI_STATUS EFIAPI FileGetInfo(EFI_FILE_HANDLE This, EFI_GUID *Type, UINTN *Len, VOID *Data) { EFI_STATUS Status; EFI_GRUB_FILE *File = _CR(This, EFI_GRUB_FILE, EfiFile); EFI_FILE_SYSTEM_INFO *FSInfo = (EFI_FILE_SYSTEM_INFO *) Data; EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data; CHAR16 GuidString[36]; EFI_TIME Time; CHAR8* label; PrintInfo(L"GetInfo(%llx|'%s', %d) %s\n", (UINT64) This, FileName(File), *Len, File->IsDir?L"<DIR>":L""); /* Determine information to return */ if (CompareMem(Type, &GenericFileInfo, sizeof(*Type)) == 0) { /* Fill file information */ PrintExtra(L"Get regular file information\n"); if (*Len < MINIMUM_INFO_LENGTH) { *Len = MINIMUM_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } ZeroMem(Data, sizeof(EFI_FILE_INFO)); Info->Attribute = EFI_FILE_READ_ONLY; GrubTimeToEfiTime(File->Mtime, &Time); CopyMem(&Info->CreateTime, &Time, sizeof(Time)); CopyMem(&Info->LastAccessTime, &Time, sizeof(Time)); CopyMem(&Info->ModificationTime, &Time, sizeof(Time)); if (File->IsDir) { Info->Attribute |= EFI_FILE_DIRECTORY; } else { Info->FileSize = GrubGetFileSize(File); Info->PhysicalSize = GrubGetFileSize(File); } Status = Utf8ToUtf16NoAlloc(File->basename, Info->FileName, (INTN)(Info->Size - sizeof(EFI_FILE_INFO))); if (EFI_ERROR(Status)) { if (Status != EFI_BUFFER_TOO_SMALL) PrintStatusError(Status, L"Could not convert basename to UTF-8"); return Status; } /* The Info struct size already accounts for the extra NUL */ Info->Size = sizeof(EFI_FILE_INFO) + StrLen(Info->FileName) * sizeof(CHAR16); return EFI_SUCCESS; } else if (CompareMem(Type, &FileSystemInfo, sizeof(*Type)) == 0) { /* Get file system information */ PrintExtra(L"Get file system information\n"); if (*Len < MINIMUM_FS_INFO_LENGTH) { *Len = MINIMUM_FS_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } ZeroMem(Data, sizeof(EFI_FILE_INFO)); FSInfo->Size = *Len; FSInfo->ReadOnly = 1; /* NB: This should really be cluster size, but we don't have access to that */ FSInfo->BlockSize = File->FileSystem->BlockIo->Media->BlockSize; if (FSInfo->BlockSize == 0) { PrintWarning(L"Corrected Media BlockSize\n"); FSInfo->BlockSize = 512; } FSInfo->VolumeSize = (File->FileSystem->BlockIo->Media->LastBlock + 1) * FSInfo->BlockSize; /* No idea if we can easily get this for GRUB, and the device is RO anyway */ FSInfo->FreeSpace = 0; Status = GrubLabel(File, &label); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not read disk label"); } else { Status = Utf8ToUtf16NoAlloc(label, FSInfo->VolumeLabel, (INTN)(FSInfo->Size - sizeof(EFI_FILE_SYSTEM_INFO))); if (EFI_ERROR(Status)) { if (Status != EFI_BUFFER_TOO_SMALL) PrintStatusError(Status, L"Could not convert label to UTF-8"); return Status; } Info->Size = sizeof(EFI_FILE_SYSTEM_INFO) + StrLen(FSInfo->VolumeLabel) * sizeof(CHAR16); } return EFI_SUCCESS; } else { GuidToString(GuidString, Type); PrintError(L"'%s': Cannot get information of type %s\n", FileName(File), GuidString); return EFI_UNSUPPORTED; } }
/** * Read directory entry * * @v file EFI file * @v Len Length to read * @v Data Data buffer * @ret Status EFI status code */ static EFI_STATUS FileReadDir(EFI_GRUB_FILE *File, UINTN *Len, VOID *Data) { EFI_FILE_INFO *Info = (EFI_FILE_INFO *) Data; EFI_STATUS Status; /* We temporarily repurpose the FileSize as a *signed* entry index */ INT64 *Index = (INT64 *) &Info->FileSize; /* And PhysicalSize as a pointer to our filename */ CHAR8 **basename = (CHAR8 **) &Info->PhysicalSize; CHAR8 path[MAX_PATH]; EFI_GRUB_FILE *TmpFile = NULL; INTN len; /* Unless we can fit our maximum size, forget it */ if (*Len < MINIMUM_INFO_LENGTH) { *Len = MINIMUM_INFO_LENGTH; return EFI_BUFFER_TOO_SMALL; } /* Populate our Info template */ ZeroMem(Data, *Len); Info->Size = *Len; *Index = File->DirIndex; strcpya(path, File->path); len = strlena(path); if (path[len-1] != '/') path[len++] = '/'; *basename = &path[len]; /* Invoke GRUB's directory listing */ Status = GrubDir(File, File->path, DirHook, Data); if (*Index >= 0) { /* No more entries */ *Len = 0; return EFI_SUCCESS; } if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Directory listing failed"); return Status; } /* Our Index/FileSize must be reset */ Info->FileSize = 0; Info->PhysicalSize = 0; /* For regular files, we still need to fill the size */ if (!(Info->Attribute & EFI_FILE_DIRECTORY)) { /* Open the file and read its size */ Status = GrubCreateFile(&TmpFile, File->FileSystem); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Unable to create temporary file"); return Status; } TmpFile->path = path; Status = GrubOpen(TmpFile); if (EFI_ERROR(Status)) { // TODO: EFI_NO_MAPPING is returned for links... PrintStatusError(Status, L"Unable to obtain the size of '%s'", Info->FileName); /* Non fatal error */ } else { Info->FileSize = GrubGetFileSize(TmpFile); Info->PhysicalSize = GrubGetFileSize(TmpFile); GrubClose(TmpFile); } GrubDestroyFile(TmpFile); } *Len = (UINTN) Info->Size; /* Advance to the next entry */ File->DirIndex++; // PrintInfo(L" Entry[%d]: '%s' %s\n", File->DirIndex-1, Info->FileName, // (Info->Attribute&EFI_FILE_DIRECTORY)?L"<DIR>":L""); return EFI_SUCCESS; }
/** * Install EFI driver - Will be the entrypoint for our driver executable * http://wiki.phoenix.com/wiki/index.php/EFI_IMAGE_ENTRY_POINT * * @v ImageHandle Handle identifying the loaded image * @v SystemTable Pointers to EFI system calls * @ret Status EFI status code to return on exit */ EFI_STATUS EFIAPI FSDriverInstall(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) { EFI_STATUS Status; EFI_LOADED_IMAGE *LoadedImage = NULL; VOID *Interface; UINTN i; InitializeLib(ImageHandle, SystemTable); SetLogging(); EfiImageHandle = ImageHandle; /* Prevent the driver from being loaded twice by detecting and trying to * instantiate a custom protocol, which we use as a global mutex. */ MutexGUID = GetFSGuid(); Status = BS->LocateProtocol(MutexGUID, NULL, &Interface); if (Status == EFI_SUCCESS) { PrintError(L"This driver has already been installed\n"); return EFI_LOAD_ERROR; } /* The only valid status we expect is NOT FOUND here */ if (Status != EFI_NOT_FOUND) { PrintStatusError(Status, L"Could not locate global mutex"); return Status; } Status = LibInstallProtocolInterfaces(&MutexHandle, MutexGUID, &MutexProtocol, NULL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not install global mutex"); return Status; } /* Grab a handle to this image, so that we can add an unload to our driver */ Status = BS->OpenProtocol(ImageHandle, &LoadedImageProtocol, (VOID **) &LoadedImage, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not open loaded image protocol"); return Status; } /* Configure driver binding protocol */ FSDriverBinding.ImageHandle = ImageHandle; FSDriverBinding.DriverBindingHandle = ImageHandle; /* Install driver */ Status = LibInstallProtocolInterfaces(&FSDriverBinding.DriverBindingHandle, &DriverBindingProtocol, &FSDriverBinding, &ComponentNameProtocol, &FSComponentName, &ComponentName2Protocol, &FSComponentName2, NULL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not bind driver"); return Status; } /* Register the uninstall callback */ LoadedImage->Unload = FSDriverUninstall; /* Initialize the relevant GRUB fs module(s) */ // TODO: Eventually, we could try to turn each GRUB module into their // own EFI driver, have them register their interface and consume that. for (i = 0; GrubModuleInit[i] != NULL; i++) GrubModuleInit[i](); InitializeListHead(&FsListHead); PrintDebug(L"FS driver installed.\n"); return EFI_SUCCESS; }
static EFI_STATUS EFIAPI FSBindingStart(EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE ControllerHandle, EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath) { EFI_STATUS Status; EFI_FS *Instance; EFI_DEVICE_PATH *DevicePath; PrintDebug(L"FSBindingStart\n"); /* Allocate a new instance of a filesystem */ Instance = AllocateZeroPool(sizeof(EFI_FS)); if (Instance == NULL) { Status = EFI_OUT_OF_RESOURCES; PrintStatusError(Status, L"Could not allocate a new file system instance"); return Status; } Instance->FileIoInterface.Revision = EFI_FILE_IO_INTERFACE_REVISION; Instance->FileIoInterface.OpenVolume = FileOpenVolume, /* Fill the device path for our instance */ DevicePath = DevicePathFromHandle(ControllerHandle); if (DevicePath == NULL) { Status = EFI_NO_MAPPING; PrintStatusError(Status, L"Could not get Device Path"); goto error; } Instance->DevicePathString = DevicePathToStr(DevicePath); if (Instance->DevicePathString == NULL) { Status = EFI_OUT_OF_RESOURCES; PrintStatusError(Status, L"Could not allocate Device Path string"); goto error; } /* Get access to the Block IO protocol for this controller */ Status = BS->OpenProtocol(ControllerHandle, &BlockIoProtocol, (VOID **) &Instance->BlockIo, This->DriverBindingHandle, ControllerHandle, /* http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES#OpenProtocol.28.29 * EFI_OPEN_PROTOCOL_BY_DRIVER returns Access Denied here, most likely * because the disk driver has that protocol already open. So we use * EFI_OPEN_PROTOCOL_GET_PROTOCOL (which doesn't require us to close it) */ EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not access BlockIO protocol"); goto error; } /* Get exclusive access to the Disk IO protocol */ Status = BS->OpenProtocol(ControllerHandle, &DiskIoProtocol, (VOID**) &Instance->DiskIo, This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not access the DiskIo protocol"); goto error; } /* Go through GRUB target init */ Status = GrubDeviceInit(Instance); if (EFI_ERROR(Status)) { PrintStatusError(Status, L"Could not init grub device"); goto error; } Status = FSInstall(Instance, ControllerHandle); /* Unless we close the DiskIO protocol in case of error, no other * FS driver will be able to access this partition. */ if (EFI_ERROR(Status)) { GrubDeviceExit(Instance); BS->CloseProtocol(ControllerHandle, &DiskIoProtocol, This->DriverBindingHandle, ControllerHandle); } error: if (EFI_ERROR(Status)) FreeFsInstance(Instance); return Status; }