mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-26 12:05:36 +01:00
292 lines
9.1 KiB
C
292 lines
9.1 KiB
C
|
/*
|
||
|
* gptsync/os_efi.c
|
||
|
* EFI glue for gptsync
|
||
|
*
|
||
|
* Copyright (c) 2006 Christoph Pfisterer
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are
|
||
|
* met:
|
||
|
*
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
*
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
*
|
||
|
* * Neither the name of Christoph Pfisterer nor the names of the
|
||
|
* contributors may be used to endorse or promote products derived
|
||
|
* from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*/
|
||
|
|
||
|
#include "gptsync.h"
|
||
|
|
||
|
// variables
|
||
|
|
||
|
EFI_BLOCK_IO_PROTOCOL *BlockIO = NULL;
|
||
|
EFI_BLOCK_IO2_PROTOCOL *BlockIO2 = NULL;
|
||
|
EFI_BLOCK_IO2_TOKEN BlockIO2Token;
|
||
|
|
||
|
//
|
||
|
// sector I/O functions
|
||
|
//
|
||
|
|
||
|
UINTN read_sector(UINT64 lba, UINT8 *buffer)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
if (BlockIO2 != NULL)
|
||
|
{
|
||
|
Status = BlockIO2->ReadBlocksEx(BlockIO2, BlockIO2->Media->MediaId, lba, &BlockIO2Token, 512, buffer);
|
||
|
} else {
|
||
|
Status = BlockIO->ReadBlocks(BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
|
||
|
}
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
// TODO: report error
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UINTN write_sector(UINT64 lba, UINT8 *buffer)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
if (BlockIO2 != NULL)
|
||
|
{
|
||
|
Status = BlockIO2->WriteBlocksEx(BlockIO2, BlockIO2->Media->MediaId, lba, &BlockIO2Token, 512, buffer);
|
||
|
} else {
|
||
|
Status = BlockIO->WriteBlocks(BlockIO, BlockIO->Media->MediaId, lba, 512, buffer);
|
||
|
}
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
// TODO: report error
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Keyboard input
|
||
|
//
|
||
|
|
||
|
static BOOLEAN ReadAllKeyStrokes(VOID)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
BOOLEAN GotKeyStrokes;
|
||
|
EFI_INPUT_KEY Key;
|
||
|
|
||
|
GotKeyStrokes = FALSE;
|
||
|
for (;;) {
|
||
|
Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
|
||
|
if (Status == EFI_SUCCESS) {
|
||
|
GotKeyStrokes = TRUE;
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return GotKeyStrokes;
|
||
|
}
|
||
|
|
||
|
static VOID PauseForKey(VOID)
|
||
|
{
|
||
|
UINTN Index;
|
||
|
|
||
|
Print(L"\n* Hit any key to continue *");
|
||
|
|
||
|
if (ReadAllKeyStrokes()) { // remove buffered key strokes
|
||
|
gBS->Stall(5000000); // 5 seconds delay
|
||
|
ReadAllKeyStrokes(); // empty the buffer again
|
||
|
}
|
||
|
|
||
|
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
|
||
|
ReadAllKeyStrokes(); // empty the buffer to protect the menu
|
||
|
|
||
|
Print(L"\n");
|
||
|
}
|
||
|
|
||
|
UINTN input_boolean(CHARN *prompt, BOOLEAN *bool_out)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINTN Index;
|
||
|
EFI_INPUT_KEY Key;
|
||
|
|
||
|
Print(prompt);
|
||
|
|
||
|
if (ReadAllKeyStrokes()) { // remove buffered key strokes
|
||
|
gBS->Stall(500000); // 0.5 seconds delay
|
||
|
ReadAllKeyStrokes(); // empty the buffer again
|
||
|
}
|
||
|
|
||
|
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &Index);
|
||
|
Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
|
||
|
if (EFI_ERROR(Status))
|
||
|
return 1;
|
||
|
|
||
|
if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
|
||
|
Print(L"Yes\n");
|
||
|
*bool_out = TRUE;
|
||
|
} else {
|
||
|
Print(L"No\n");
|
||
|
*bool_out = FALSE;
|
||
|
}
|
||
|
|
||
|
ReadAllKeyStrokes();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// main entry point
|
||
|
//
|
||
|
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
GptSyncMain (IN EFI_HANDLE ImageHandle,
|
||
|
IN EFI_SYSTEM_TABLE *SystemTable)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_STATUS Status2;
|
||
|
UINTN SyncStatus;
|
||
|
UINTN Index;
|
||
|
UINTN HandleCount;
|
||
|
UINTN HandleCount2;
|
||
|
EFI_HANDLE *HandleBuffer = NULL;
|
||
|
EFI_HANDLE *HandleBuffer2 = NULL;
|
||
|
EFI_HANDLE DeviceHandle;
|
||
|
EFI_DEVICE_PATH *DevicePath, *NextDevicePath;
|
||
|
BOOLEAN Usable;
|
||
|
|
||
|
Status = gBS->LocateHandle(ByProtocol, &gEfiBlockIo2ProtocolGuid, NULL,
|
||
|
&HandleCount2, NULL);
|
||
|
|
||
|
Status = gBS->LocateHandle(ByProtocol, &gEfiBlockIoProtocolGuid, NULL,
|
||
|
&HandleCount, NULL);
|
||
|
|
||
|
if (!HandleCount && !HandleCount2)
|
||
|
{
|
||
|
Status = EFI_NOT_FOUND;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
HandleBuffer = AllocateZeroPool(HandleCount * sizeof(EFI_HANDLE));
|
||
|
|
||
|
HandleBuffer2 = AllocateZeroPool(HandleCount2 * sizeof(EFI_HANDLE));
|
||
|
|
||
|
Status2 = gBS->LocateHandle(ByProtocol, &gEfiBlockIo2ProtocolGuid, NULL,
|
||
|
&HandleCount2, HandleBuffer2);
|
||
|
|
||
|
Status = gBS->LocateHandle(ByProtocol, &gEfiBlockIoProtocolGuid, NULL,
|
||
|
&HandleCount, HandleBuffer);
|
||
|
if (EFI_ERROR (Status) && EFI_ERROR (Status2)) {
|
||
|
Status = EFI_NOT_FOUND;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
for (Index = 0; Index < HandleCount2; Index++) {
|
||
|
|
||
|
DeviceHandle = HandleBuffer2[Index];
|
||
|
|
||
|
// check device path
|
||
|
DevicePath = DevicePathFromHandle(DeviceHandle);
|
||
|
Usable = TRUE;
|
||
|
while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
|
||
|
NextDevicePath = NextDevicePathNode(DevicePath);
|
||
|
|
||
|
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
|
||
|
(DevicePathSubType(DevicePath) == MSG_USB_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_1394_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
|
||
|
Usable = FALSE; // USB/FireWire/FC device
|
||
|
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH)
|
||
|
Usable = FALSE; // partition, El Torito entry, legacy BIOS device
|
||
|
|
||
|
DevicePath = NextDevicePath;
|
||
|
}
|
||
|
if (!Usable)
|
||
|
continue;
|
||
|
|
||
|
Status = gBS->HandleProtocol(DeviceHandle, &gEfiBlockIo2ProtocolGuid, (VOID **) &BlockIO2);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
// TODO: report error
|
||
|
BlockIO = NULL;
|
||
|
} else {
|
||
|
if (BlockIO2->Media->BlockSize != 512)
|
||
|
BlockIO2 = NULL; // optical media
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
FreePool (HandleBuffer2);
|
||
|
|
||
|
for (Index = 0; Index < HandleCount; Index++) {
|
||
|
|
||
|
DeviceHandle = HandleBuffer[Index];
|
||
|
|
||
|
// check device path
|
||
|
DevicePath = DevicePathFromHandle(DeviceHandle);
|
||
|
Usable = TRUE;
|
||
|
while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
|
||
|
NextDevicePath = NextDevicePathNode(DevicePath);
|
||
|
|
||
|
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
|
||
|
(DevicePathSubType(DevicePath) == MSG_USB_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_1394_DP ||
|
||
|
DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP))
|
||
|
Usable = FALSE; // USB/FireWire/FC device
|
||
|
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH)
|
||
|
Usable = FALSE; // partition, El Torito entry, legacy BIOS device
|
||
|
|
||
|
DevicePath = NextDevicePath;
|
||
|
}
|
||
|
if (!Usable)
|
||
|
continue;
|
||
|
|
||
|
Status = gBS->HandleProtocol(DeviceHandle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIO);
|
||
|
if (EFI_ERROR(Status)) {
|
||
|
// TODO: report error
|
||
|
BlockIO = NULL;
|
||
|
} else {
|
||
|
if (BlockIO->Media->BlockSize != 512)
|
||
|
BlockIO = NULL; // optical media
|
||
|
else
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
FreePool (HandleBuffer);
|
||
|
|
||
|
if ((BlockIO == NULL) && (BlockIO2 == NULL)) {
|
||
|
Print(L"Internal hard disk device not found!\n");
|
||
|
return EFI_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
SyncStatus = gptsync();
|
||
|
|
||
|
if (SyncStatus == 0)
|
||
|
PauseForKey();
|
||
|
|
||
|
if (SyncStatus)
|
||
|
return EFI_NOT_FOUND;
|
||
|
|
||
|
return EFI_SUCCESS;
|
||
|
}
|