mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-10 09:40:53 +01:00
7b8e787751
Signed-off-by: SergeySlice <sergey.slice@gmail.com>
672 lines
20 KiB
C++
672 lines
20 KiB
C++
/*
|
|
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
*/
|
|
|
|
#include <Platform.h>
|
|
#include <Efi.h>
|
|
|
|
#include "../entry_scan/entry_scan.h"
|
|
//#include "device_tree.h"
|
|
#include "kernel_patcher.h"
|
|
#include "usbfix.h"
|
|
#include "../Platform/cpu.h"
|
|
#include "../Platform/Settings.h"
|
|
|
|
#ifndef DEBUG_ALL
|
|
#define PATCH_DEBUG 0
|
|
#define MEM_DEB 0
|
|
#else
|
|
#define PATCH_DEBUG DEBUG_ALL
|
|
#define MEM_DEB DEBUG_ALL
|
|
#endif
|
|
|
|
#if PATCH_DEBUG
|
|
#define DBG(...) printf(__VA_ARGS__);
|
|
#else
|
|
#define DBG(...)
|
|
#endif
|
|
|
|
////
|
|
//// Max bytes needed to represent ID of a SCSI device
|
|
////
|
|
//#define EFI_SCSI_TARGET_MAX_BYTES (0x10)
|
|
////
|
|
//// bit5..7 are for Logical unit number
|
|
//// 11100000b (0xe0)
|
|
////
|
|
//#define EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK 0xe0
|
|
|
|
|
|
//
|
|
// Scsi Command Length
|
|
//
|
|
#define EFI_SCSI_OP_LENGTH_SIX 0x6
|
|
//#define EFI_SCSI_OP_LENGTH_TEN 0xa
|
|
//#define EFI_SCSI_OP_LENGTH_SIXTEEN 0x10
|
|
|
|
|
|
|
|
EFI_EVENT mVirtualAddressChangeEvent = NULL;
|
|
EFI_EVENT OnReadyToBootEvent = NULL;
|
|
EFI_EVENT ExitBootServiceEvent = NULL;
|
|
EFI_EVENT mSimpleFileSystemChangeEvent = NULL;
|
|
EFI_HANDLE mHandle = NULL;
|
|
|
|
extern EFI_RUNTIME_SERVICES gOrgRS;
|
|
|
|
/*
|
|
void WaitForCR()
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY key;
|
|
UINTN ind;
|
|
|
|
while (true) {
|
|
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &key);
|
|
if (Status == EFI_NOT_READY) {
|
|
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &ind);
|
|
continue;
|
|
}
|
|
if (key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
#if 0
|
|
//this procedure was developed for 10.5. Seems no more needed
|
|
void CorrectMemoryMap(IN UINT32 memMap,
|
|
IN UINT32 memDescriptorSize,
|
|
IN OUT UINT32 *memMapSize)
|
|
{
|
|
EfiMemoryRange* memDescriptor;
|
|
UINT64 Bytes;
|
|
UINT32 Index;
|
|
CHAR16 tmp[80];
|
|
EFI_INPUT_KEY Key;
|
|
// UINTN ind;
|
|
//
|
|
//step 1. Check for last empty descriptors
|
|
//
|
|
// PauseForKey(L"Check for last empty descriptors");
|
|
// gST->ConOut->OutputString (gST->ConOut, L"Check for last empty descriptors\n\r");
|
|
// gBS->Stall(2000000);
|
|
memDescriptor = (EfiMemoryRange *)(UINTN)(memMap + *memMapSize - memDescriptorSize);
|
|
while ((memDescriptor->NumberOfPages == 0) || (memDescriptor->NumberOfPages > (1<<25)))
|
|
{
|
|
memDescriptor = (EfiMemoryRange *)((UINTN)memDescriptor - memDescriptorSize);
|
|
*memMapSize -= memDescriptorSize;
|
|
}
|
|
//
|
|
//step 2. Add last desc about MEM4GB
|
|
//
|
|
/* if (gTotalMemory > MEM4GB) {
|
|
//next descriptor
|
|
memDescriptor = (EfiMemoryRange *)((UINTN)memDescriptor + memDescriptorSize);
|
|
memDescriptor->Type = EfiConventionalMemory;
|
|
memDescriptor->PhysicalStart = MEM4GB;
|
|
memDescriptor->VirtualStart = MEM4GB;
|
|
memDescriptor->NumberOfPages = LShiftU64(gTotalMemory - MEM4GB, EFI_PAGE_SHIFT);
|
|
memDescriptor->Attribute = 0;
|
|
*memMapSize += memDescriptorSize;
|
|
}
|
|
*/
|
|
memDescriptor = (EfiMemoryRange *)(UINTN)memMap;
|
|
for (Index = 0; Index < *memMapSize / memDescriptorSize; Index ++) {
|
|
//
|
|
//step 3. convert BootServiceData to conventional
|
|
// not needed as performed by mach_kernel
|
|
/* switch (memDescriptor->Type) {
|
|
case EfiLoaderData:
|
|
case EfiBootServicesCode:
|
|
case EfiBootServicesData:
|
|
memDescriptor->Type = EfiConventionalMemory;
|
|
memDescriptor->Attribute = 0;
|
|
// DBG(L"Range BS %hhX corrected to conventional\n", memDescriptor->PhysicalStart);
|
|
if(MEM_DEB) {
|
|
snwprintf(tmp, 160, "Range BS %hhX corrected to conventional\n\r", memDescriptor->PhysicalStart);
|
|
gST->ConOut->OutputString (gST->ConOut, tmp);
|
|
// gBS->Stall(2000000);
|
|
WaitForCR();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
*/
|
|
//
|
|
//step 4. free reserved memory if cachable
|
|
if ((memDescriptor->Type == EfiReservedMemoryType) &&
|
|
(memDescriptor->Attribute == EFI_MEMORY_WB)) {
|
|
memDescriptor->Type = EfiConventionalMemory;
|
|
memDescriptor->Attribute = 0xF;
|
|
// DBG(L"Range WB %hhX corrected to conventional\n", memDescriptor->PhysicalStart);
|
|
if(MEM_DEB) {
|
|
snwprintf(tmp, 160, "Range WB %hhX corrected to conventional\n\r", memDescriptor->PhysicalStart);
|
|
gST->ConOut->OutputString (gST->ConOut, tmp);
|
|
//gBS->Stall(2000000);
|
|
// WaitForCR();
|
|
}
|
|
}
|
|
//
|
|
//step 5. free reserved memory if base >= 20000 & <= 60000
|
|
//xxx
|
|
if ((memDescriptor->Type == EfiReservedMemoryType) &&
|
|
(memDescriptor->PhysicalStart >= 0x20000000) &&
|
|
(memDescriptor->PhysicalStart <= 0x60000000)) {
|
|
memDescriptor->Type = EfiConventionalMemory;
|
|
memDescriptor->Attribute = 0xF;
|
|
}
|
|
//
|
|
}
|
|
//step 6. Reserve for 9E
|
|
memDescriptor = (EfiMemoryRange *)((UINTN)memDescriptor + memDescriptorSize);
|
|
memDescriptor->Type = EfiReservedMemoryType;
|
|
memDescriptor->PhysicalStart = 0x9e000;
|
|
memDescriptor->VirtualStart = 0x9e000;
|
|
memDescriptor->NumberOfPages = 2;
|
|
memDescriptor->Attribute = 0;
|
|
*memMapSize += memDescriptorSize;
|
|
|
|
|
|
if(MEM_DEB) {
|
|
gST->ConOut->OutputString (gST->ConOut, L"press any key to dump MemoryMap\r\n");
|
|
// gBS->Stall(2000000);
|
|
WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
|
|
|
|
gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
|
|
// PauseForKey(L"press any key to dump MemoryMap");
|
|
memDescriptor = (EfiMemoryRange *)(UINTN)memMap;
|
|
for (Index = 0; Index < *memMapSize / memDescriptorSize; Index ++) {
|
|
Bytes = LShiftU64 (memDescriptor->NumberOfPages, 12);
|
|
snwprintf(tmp, 160, "%lX-%lX pages %lX type %lX attr %hhX \r\n\r\t",
|
|
memDescriptor->PhysicalStart,
|
|
memDescriptor->PhysicalStart + Bytes - 1,
|
|
memDescriptor->NumberOfPages,
|
|
(UINTN)memDescriptor->Type,
|
|
memDescriptor->Attribute
|
|
);
|
|
gST->ConOut->OutputString (gST->ConOut, tmp);
|
|
// gBS->Stall(2000000);
|
|
|
|
memDescriptor = (EfiMemoryRange *)((UINTN)memDescriptor + memDescriptorSize);
|
|
if (Index % 20 == 19) {
|
|
gST->ConOut->OutputString (gST->ConOut, L"press any key\r\n");
|
|
WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
|
|
// gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
|
|
/* if (ReadAllKeyStrokes()) { // remove buffered key strokes
|
|
gBS->Stall(5000000); // 5 seconds delay
|
|
ReadAllKeyStrokes(); // empty the buffer again
|
|
}
|
|
|
|
gBS->WaitForEvent(1, &gST->ConIn->WaitForKey, &ind);
|
|
ReadAllKeyStrokes(); // empty the buffer to protect the menu
|
|
WaitForCR();
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
#endif
|
|
|
|
void
|
|
EFIAPI
|
|
OnExitBootServices(IN EFI_EVENT Event, IN void *Context)
|
|
{
|
|
/*
|
|
if (gCPUStructure.Vendor == CPU_VENDOR_INTEL &&
|
|
(gCPUStructure.Family == 0x06 && gCPUStructure.Model >= CPU_MODEL_SANDY_BRIDGE)
|
|
) {
|
|
UINT64 msr = 0;
|
|
|
|
msr = AsmReadMsr64(MSR_PKG_CST_CONFIG_CONTROL); //0xE2
|
|
// printf("MSR 0xE2 on Exit BS %08x\n", msr);
|
|
|
|
} */
|
|
/*
|
|
// EFI_STATUS Status;
|
|
{
|
|
// UINT32 machineSignature = 0;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs = NULL;
|
|
|
|
// DBG("---dump hibernations data---\n");
|
|
FadtPointer = GetFadt();
|
|
if (FadtPointer != NULL) {
|
|
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)(FadtPointer->FirmwareCtrl);
|
|
|
|
printf(" Firmware wake address=%08lx\n", Facs->FirmwareWakingVector);
|
|
printf(" Firmware wake 64 addr=%16llx\n", Facs->XFirmwareWakingVector);
|
|
printf(" Hardware signature =%08lx\n", Facs->HardwareSignature);
|
|
printf(" GlobalLock =%08lx\n", Facs->GlobalLock);
|
|
printf(" Flags =%08lx\n", Facs->Flags);
|
|
printf(" HS at offset 0x%08x\n", OFFSET_OF(EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE, HardwareSignature));
|
|
// machineSignature = Facs->HardwareSignature;
|
|
}
|
|
}
|
|
*/
|
|
|
|
gST->ConOut->OutputString (gST->ConOut, L"+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
|
|
//
|
|
// Patch kernel and kexts if needed
|
|
//
|
|
// Jief : OpenCore is doing the kernel patching for all versions.
|
|
// LOADER_ENTRY *Entry = ((REFIT_ABSTRACT_MENU_ENTRY*)Context)->getLOADER_ENTRY();
|
|
// if ( Entry && Entry->OSVersion.startWith("10") ) {
|
|
// Entry->KernelAndKextsPatcherStart();
|
|
// }
|
|
|
|
#if 0 //it will be as a sample of possible patches in future
|
|
// gBS->Stall(2000000);
|
|
//PauseForKey(L"press any key to MemoryFix");
|
|
if (gSettings.MemoryFix) {
|
|
BootArgs1* bootArgs1v;
|
|
BootArgs2* bootArgs2v;
|
|
UINT8* ptr=(UINT8*)(UINTN)0x100000;
|
|
// DTEntry efiPlatform;
|
|
// CHAR8* dtreeRoot;
|
|
UINTN archMode = sizeof(UINTN) * 8;
|
|
UINTN Version = 0;
|
|
|
|
while(true)
|
|
{
|
|
bootArgs2v = (BootArgs2*)ptr;
|
|
bootArgs1v = (BootArgs1*)ptr;
|
|
|
|
/* search bootargs for 10.7 */
|
|
if(((bootArgs2v->Revision == 0) || (bootArgs2v->Revision == 1)) && bootArgs2v->Version==2)
|
|
{
|
|
if (((UINTN)bootArgs2v->efiMode == 32) || ((UINTN)bootArgs2v->efiMode == 64)){
|
|
// dtreeRoot = (CHAR8*)(UINTN)bootArgs2v->deviceTreeP;
|
|
bootArgs2v->efiMode = (UINT8)archMode; //correct to EFI arch
|
|
Version = 2;
|
|
// DBG(L"found bootarg v2");
|
|
gST->ConOut->OutputString (gST->ConOut, L"found bootarg v2");
|
|
break;
|
|
}
|
|
|
|
/* search bootargs for 10.4 - 10.6.x */
|
|
} else if(((bootArgs1v->Revision==6) ||
|
|
(bootArgs1v->Revision==5) ||
|
|
(bootArgs1v->Revision==4)) &&
|
|
(bootArgs1v->Version ==1)){
|
|
|
|
if (((UINTN)bootArgs1v->efiMode == 32) ||
|
|
((UINTN)bootArgs1v->efiMode == 64)){
|
|
// dtreeRoot = (CHAR8*)(UINTN)bootArgs1v->deviceTreeP;
|
|
bootArgs1v->efiMode = (UINT8)archMode;
|
|
Version = 1;
|
|
// DBG(L"found bootarg v1");
|
|
gST->ConOut->OutputString (gST->ConOut, L"found bootarg v1");
|
|
break;
|
|
}
|
|
}
|
|
|
|
ptr+=0x1000;
|
|
if((UINT32)(UINTN)ptr > 0x3000000)
|
|
{
|
|
// DBG("bootArgs not found!\n");
|
|
gST->ConOut->OutputString (gST->ConOut, L"bootArgs not found!");
|
|
gBS->Stall(5000000);
|
|
// return;
|
|
break;
|
|
}
|
|
}
|
|
if(Version==2) {
|
|
CorrectMemoryMap(bootArgs2v->MemoryMap,
|
|
bootArgs2v->MemoryMapDescriptorSize,
|
|
&bootArgs2v->MemoryMapSize);
|
|
// bootArgs2v->efiSystemTable = (UINT32)(UINTN)gST;
|
|
|
|
}else if(Version==1) {
|
|
CorrectMemoryMap(bootArgs1v->MemoryMap,
|
|
bootArgs1v->MemoryMapDescriptorSize,
|
|
&bootArgs1v->MemoryMapSize);
|
|
// bootArgs1v->efiSystemTable = (UINT32)(UINTN)gST;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (gSettings.Devices.USB.USBFixOwnership) {
|
|
FixOwnership();
|
|
}
|
|
}
|
|
|
|
void
|
|
EFIAPI
|
|
OnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN void *Context
|
|
)
|
|
{
|
|
/*
|
|
if ((gCPUStructure.Vendor == CPU_VENDOR_INTEL &&
|
|
(gCPUStructure.Family == 0x06 && gCPUStructure.Model >= CPU_MODEL_SANDY_BRIDGE)
|
|
)) {
|
|
UINT64 msr = 0;
|
|
|
|
msr = AsmReadMsr64(MSR_PKG_CST_CONFIG_CONTROL); //0xE2
|
|
|
|
}
|
|
// printf("MSR 0xE2 on ReadyToBoot %08x\n", msr);
|
|
*/
|
|
gST->ConOut->OutputString (gST->ConOut, L"-- ReadyToBoot --\n");
|
|
}
|
|
|
|
void
|
|
EFIAPI
|
|
VirtualAddressChangeEvent (
|
|
IN EFI_EVENT Event,
|
|
IN void *Context
|
|
)
|
|
{
|
|
// EfiConvertPointer (0x0, (void **) &mProperty);
|
|
// EfiConvertPointer (0x0, (void **) &mSmmCommunication);
|
|
}
|
|
|
|
void
|
|
EFIAPI
|
|
OnSimpleFileSystem (
|
|
IN EFI_EVENT Event,
|
|
IN void *Context
|
|
)
|
|
{
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
|
|
gEvent = 1;
|
|
// ReinitRefitLib();
|
|
//ScanVolumes();
|
|
//enter GUI
|
|
// DrawMenuText(L"OnSimpleFileSystem", 0, 0, UGAHeight-40, 1);
|
|
// MsgLog("OnSimpleFileSystem occured\n");
|
|
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
GuiEventsInitialize ()
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_EVENT Event;
|
|
void* RegSimpleFileSystem = NULL;
|
|
|
|
gEvent = 0;
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
OnSimpleFileSystem,
|
|
NULL,
|
|
&Event);
|
|
if(!EFI_ERROR(Status))
|
|
{
|
|
Status = gBS->RegisterProtocolNotify (
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
Event,
|
|
&RegSimpleFileSystem);
|
|
}
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
//EFI_STATUS
|
|
//WaitForSingleEvent (
|
|
// IN EFI_EVENT Event,
|
|
// IN UINT64 Timeout OPTIONAL
|
|
// )
|
|
//{
|
|
// EFI_STATUS Status;
|
|
// UINTN Index;
|
|
//
|
|
// EFI_EVENT WaitList[3];
|
|
// EFI_EVENT TimerEvent;
|
|
//
|
|
// if (Timeout != 0)
|
|
// {
|
|
// //
|
|
// // Create a timer event
|
|
// //
|
|
// Status = gBS->CreateEvent(EVT_TIMER, 0, NULL, NULL, &TimerEvent);
|
|
// if (!EFI_ERROR(Status))
|
|
// {
|
|
// //
|
|
// // Set the timer event
|
|
// //
|
|
// gBS->SetTimer(TimerEvent, TimerRelative, Timeout);
|
|
//
|
|
// //
|
|
// // Wait for the original event or the timer
|
|
// //
|
|
// WaitList[0] = Event;
|
|
// WaitList[1] = TimerEvent;
|
|
//
|
|
// Status = gBS->WaitForEvent(2, WaitList, &Index);
|
|
// gBS->CloseEvent (TimerEvent);
|
|
// if (!EFI_ERROR(Status) && Index == 1)
|
|
// {
|
|
// Status = EFI_TIMEOUT;
|
|
// }
|
|
// }
|
|
// }
|
|
// else
|
|
// {
|
|
// WaitList[0] = Event;
|
|
// Status = gBS->WaitForEvent (1, WaitList, &Index);
|
|
// }
|
|
// return Status;
|
|
//}
|
|
//
|
|
|
|
//set Timeout in ms
|
|
EFI_STATUS
|
|
WaitFor2EventWithTsc (
|
|
IN EFI_EVENT Event1,
|
|
IN EFI_EVENT Event2,
|
|
IN UINT64 Timeout OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN Index;
|
|
EFI_EVENT WaitList[2];
|
|
UINT64 t0, t1;
|
|
//all arguments are UINT64, we can use native divide and multiply
|
|
UINT64 Delta = DivU64x64Remainder(MultU64x64(Timeout, gCPUStructure.TSCFrequency), 1000, NULL);
|
|
|
|
if (Timeout != 0)
|
|
{
|
|
t0 = AsmReadTsc();
|
|
do {
|
|
Status = gBS->CheckEvent(Event1);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
if (Event2) {
|
|
Status = gBS->CheckEvent(Event2);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
// Let's try to relax processor a bit
|
|
CpuPause();
|
|
Status = EFI_TIMEOUT;
|
|
t1 = AsmReadTsc();
|
|
} while ((t1 - t0) < Delta);
|
|
}
|
|
else
|
|
{
|
|
WaitList[0] = Event1;
|
|
WaitList[1] = Event2;
|
|
Status = gBS->WaitForEvent (2, WaitList, &Index);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
EventsInitialize (IN LOADER_ENTRY *Entry)
|
|
{
|
|
EFI_STATUS Status;
|
|
void* Registration = NULL;
|
|
|
|
//
|
|
// Register the event to reclaim variable for OS usage.
|
|
//
|
|
//EfiCreateEventReadyToBoot(&OnReadyToBootEvent);
|
|
/* EfiCreateEventReadyToBootEx (
|
|
TPL_NOTIFY,
|
|
OnReadyToBoot,
|
|
NULL,
|
|
&OnReadyToBootEvent
|
|
); */
|
|
|
|
//
|
|
// Register notify for exit boot services
|
|
//
|
|
Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_CALLBACK,
|
|
OnExitBootServices,
|
|
Entry,
|
|
&ExitBootServiceEvent);
|
|
|
|
if(!EFI_ERROR(Status))
|
|
{
|
|
/*Status = */gBS->RegisterProtocolNotify (
|
|
&gEfiStatusCodeRuntimeProtocolGuid,
|
|
ExitBootServiceEvent,
|
|
&Registration);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Register the event to convert the pointer for runtime.
|
|
//
|
|
/*
|
|
gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
VirtualAddressChangeEvent,
|
|
NULL,
|
|
&gEfiEventVirtualAddressChangeGuid,
|
|
&mVirtualAddressChangeEvent
|
|
);
|
|
*/
|
|
// and what if EFI_ERROR?
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS EjectVolume(IN REFIT_VOLUME *Volume)
|
|
{
|
|
EFI_SCSI_IO_PROTOCOL *ScsiIo = NULL;
|
|
EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;
|
|
// UINT64 Lun = 0;
|
|
// UINT8 *Target;
|
|
// UINT8 TargetArray[EFI_SCSI_TARGET_MAX_BYTES];
|
|
EFI_STATUS Status; // = EFI_UNSUPPORTED;
|
|
UINT8 Cdb[EFI_SCSI_OP_LENGTH_SIX];
|
|
USB_MASS_DEVICE *UsbMass = NULL;
|
|
EFI_BLOCK_IO_PROTOCOL *BlkIo = NULL;
|
|
EFI_BLOCK_IO_MEDIA *Media;
|
|
UINT32 Timeout;
|
|
UINT32 CmdResult;
|
|
|
|
//
|
|
// Initialize SCSI REQUEST_PACKET and 6-byte Cdb
|
|
//
|
|
ZeroMem (&CommandPacket, sizeof (EFI_SCSI_IO_SCSI_REQUEST_PACKET));
|
|
ZeroMem (Cdb, EFI_SCSI_OP_LENGTH_SIX);
|
|
|
|
Status = gBS->HandleProtocol(Volume->DeviceHandle, &gEfiScsiIoProtocolGuid, (void **) &ScsiIo);
|
|
if (ScsiIo) {
|
|
// Target = &TargetArray[0];
|
|
// ScsiIo->GetDeviceLocation (ScsiIo, &Target, &Lun);
|
|
|
|
|
|
Cdb[0] = EFI_SCSI_OP_START_STOP_UNIT;
|
|
// Cdb[1] = (UINT8) (LShiftU64 (Lun, 5) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
|
|
// Cdb[1] |= 0x01;
|
|
Cdb[1] = 0x01;
|
|
Cdb[4] = ATA_CMD_SUBOP_EJECT_DISC;
|
|
CommandPacket.Timeout = EFI_TIMER_PERIOD_SECONDS (3);
|
|
CommandPacket.Cdb = Cdb;
|
|
CommandPacket.CdbLength = (UINT8) sizeof (Cdb);
|
|
|
|
Status = ScsiIo->ExecuteScsiCommand (ScsiIo, &CommandPacket, NULL);
|
|
} else {
|
|
Status = gBS->HandleProtocol(Volume->DeviceHandle, &gEfiBlockIoProtocolGuid, (void **) &BlkIo);
|
|
if (BlkIo) {
|
|
UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlkIo);
|
|
if (!UsbMass) {
|
|
MsgLog("no UsbMass\n");
|
|
Status = EFI_NOT_FOUND;
|
|
goto ON_EXIT;
|
|
}
|
|
Media = &UsbMass->BlockIoMedia;
|
|
if (!Media) {
|
|
MsgLog("no BlockIoMedia\n");
|
|
Status = EFI_NO_MEDIA;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// If it is a removable media, such as CD-Rom or Usb-Floppy,
|
|
// need to detect the media before each read/write. While some of
|
|
// Usb-Flash is marked as removable media.
|
|
//
|
|
//TODO - DetectMedia will appear automatically. Do nothing?
|
|
if (!Media->RemovableMedia) {
|
|
//Status = UsbBootDetectMedia (UsbMass);
|
|
// if (EFI_ERROR(Status)) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto ON_EXIT;
|
|
// }
|
|
}
|
|
|
|
if (!(Media->MediaPresent)) {
|
|
Status = EFI_NO_MEDIA;
|
|
goto ON_EXIT;
|
|
}
|
|
//TODO - remember previous state
|
|
/* if (MediaId != Media->MediaId) {
|
|
Status = EFI_MEDIA_CHANGED;
|
|
goto ON_EXIT;
|
|
}*/
|
|
|
|
Timeout = USB_BOOT_GENERAL_CMD_TIMEOUT;
|
|
Cdb[0] = EFI_SCSI_OP_START_STOP_UNIT;
|
|
// Cdb[1] = (UINT8) (USB_BOOT_LUN(UsbMass->Lun) & EFI_SCSI_LOGICAL_UNIT_NUMBER_MASK);
|
|
// Cdb[1] |= 0x01;
|
|
Cdb[1] = 0x01;
|
|
Cdb[4] = ATA_CMD_SUBOP_EJECT_DISC; //eject command.
|
|
// Status = EFI_UNSUPPORTED;
|
|
Status = UsbMass->Transport->ExecCommand (
|
|
UsbMass->Context,
|
|
&Cdb,
|
|
sizeof(Cdb),
|
|
EfiUsbDataOut,
|
|
NULL, 0,
|
|
UsbMass->Lun,
|
|
Timeout,
|
|
&CmdResult
|
|
);
|
|
|
|
//ON_EXIT:
|
|
// gBS->RestoreTPL (OldTpl);
|
|
}
|
|
}
|
|
ON_EXIT:
|
|
return Status;
|
|
}
|