1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/zsl588-OpenCorePkg

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
OcApfsConnect.c 15 КБ
Копировать Редактировать Исходные данные Просмотреть построчно История
Vitaly Cheptsov Отправлено 4 лет назад f1eeae4
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
/** @file
Copyright (C) 2020, vit9696. All rights reserved.
All rights reserved.
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 "OcApfsInternal.h"
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcApfsLib.h>
#include <Library/OcPeCoffExtLib.h>
#include <Library/OcAppleSecureBootLib.h>
#include <Library/OcBootManagementLib.h>
#include <Library/OcConsoleLib.h>
#include <Library/OcDriverConnectionLib.h>
#include <Library/OcGuardLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Guid/OcVariable.h>
#include <Protocol/ApfsUnsupportedBds.h>
#include <Protocol/DevicePath.h>
#include <Protocol/LoadedImage.h>
#include <Protocol/SimpleFileSystem.h>
LIST_ENTRY mApfsPrivateDataList = INITIALIZE_LIST_HEAD_VARIABLE (mApfsPrivateDataList);
STATIC UINT64 mApfsMinimalVersion = OC_APFS_VERSION_DEFAULT;
STATIC UINT32 mApfsMinimalDate = OC_APFS_DATE_DEFAULT;
STATIC UINT32 mOcScanPolicy;
STATIC BOOLEAN mIgnoreVerbose;
STATIC BOOLEAN mGlobalConnect;
STATIC BOOLEAN mDisconnectHandles;
STATIC EFI_SYSTEM_TABLE *mNullSystemTable;
//
// There seems to exist a driver with a very large version, which is treated by
// apfs kernel extension to have 0 version. Follow suit.
//
STATIC UINT64 mApfsBlacklistedVersions[] = {
4294966999999999999ULL
};
STATIC
EFI_STATUS
ApfsCheckOpenCoreScanPolicy (
IN EFI_HANDLE Handle
)
{
UINT32 ScanPolicy;
//
// If filesystem limitations are set and APFS is not allowed,
// report failure.
//
if ((mOcScanPolicy & OC_SCAN_FILE_SYSTEM_LOCK) != 0
&& (mOcScanPolicy & OC_SCAN_ALLOW_FS_APFS) == 0) {
return EFI_UNSUPPORTED;
}
//
// If device type locking is set and this device is not allowed,
// report failure.
//
if ((mOcScanPolicy & OC_SCAN_DEVICE_LOCK) != 0) {
ScanPolicy = OcGetDevicePolicyType (Handle, NULL);
if ((ScanPolicy & mOcScanPolicy) == 0) {
return EFI_UNSUPPORTED;
}
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
ApfsVerifyDriverVersion (
IN APFS_PRIVATE_DATA *PrivateData,
IN VOID *DriverBuffer,
IN UINT32 DriverSize
)
{
EFI_STATUS Status;
APFS_DRIVER_VERSION *DriverVersion;
UINT64 RealVersion;
UINT32 RealDate;
UINTN Index;
BOOLEAN HasLegitVersion;
Status = PeCoffGetApfsDriverVersion (
DriverBuffer,
DriverSize,
&DriverVersion
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_WARN,
"OCJS: No APFS driver version found for %g - %r\n",
&PrivateData->LocationInfo.ContainerUuid,
Status
));
RealVersion = 22; ///< From apfs kernel extension.
RealDate = 0;
} else {
RealVersion = DriverVersion->Version;
RealDate = 0;
//
// Parse YYYY/MM/DD date.
//
for (Index = 0; Index < 10; ++Index) {
if ((Index == 4 || Index == 7)) {
if (DriverVersion->Date[Index] != '/') {
RealDate = 0;
break;
}
continue;
}
if (DriverVersion->Date[Index] < '0' || DriverVersion->Date[Index] > '9') {
RealDate = 0;
break;
}
RealDate *= 10;
RealDate += DriverVersion->Date[Index] - '0';
}
if (RealDate == 0) {
DEBUG ((
DEBUG_WARN,
"OCJS: APFS driver date is invalid for %g\n",
&PrivateData->LocationInfo.ContainerUuid
));
}
}
for (Index = 0; Index < ARRAY_SIZE (mApfsBlacklistedVersions); ++Index) {
if (RealVersion == mApfsBlacklistedVersions[Index]) {
DEBUG ((
DEBUG_WARN,
"OCJS: APFS driver version %Lu is blacklisted for %g, treating as 0\n",
DriverVersion->Version,
&PrivateData->LocationInfo.ContainerUuid
));
RealVersion = 0;
break;
}
}
HasLegitVersion = (mApfsMinimalVersion == 0 || mApfsMinimalVersion <= RealVersion)
&& (mApfsMinimalDate == 0 || mApfsMinimalDate <= RealDate);
DEBUG ((
DEBUG_INFO,
"OCJS: APFS driver %Lu/%u found for %g, required >= %Lu/%u, %a\n",
RealVersion,
RealDate,
&PrivateData->LocationInfo.ContainerUuid,
mApfsMinimalVersion,
mApfsMinimalDate,
HasLegitVersion ? "allow" : "prohibited"
));
if (HasLegitVersion) {
return EFI_SUCCESS;
}
return EFI_SECURITY_VIOLATION;
}
STATIC
EFI_STATUS
ApfsRegisterPartition (
IN EFI_HANDLE Handle,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN APFS_NX_SUPERBLOCK *SuperBlock,
OUT APFS_PRIVATE_DATA **PrivateDataPointer
)
{
EFI_STATUS Status;
APFS_PRIVATE_DATA *PrivateData;
PrivateData = AllocateZeroPool (sizeof (*PrivateData));
if (PrivateData == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// File private data fields.
//
PrivateData->Signature = APFS_PRIVATE_DATA_SIGNATURE;
PrivateData->LocationInfo.ControllerHandle = Handle;
CopyGuid (&PrivateData->LocationInfo.ContainerUuid, &SuperBlock->Uuid);
PrivateData->BlockIo = BlockIo;
PrivateData->ApfsBlockSize = SuperBlock->BlockSize;
PrivateData->LbaMultiplier = PrivateData->ApfsBlockSize / PrivateData->BlockIo->Media->BlockSize;
PrivateData->EfiJumpStart = SuperBlock->EfiJumpStart;
InternalApfsInitFusionData (SuperBlock, PrivateData);
//
// Install boot record information.
// This guarantees us that we never register twice.
//
Status = gBS->InstallMultipleProtocolInterfaces (
&PrivateData->LocationInfo.ControllerHandle,
&gApfsEfiBootRecordInfoProtocolGuid,
&PrivateData->LocationInfo,
NULL
);
if (EFI_ERROR (Status)) {
FreePool (PrivateData);
return Status;
}
//
// Save into the list and return.
//
InsertTailList (&mApfsPrivateDataList, &PrivateData->Link);
*PrivateDataPointer = PrivateData;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
ApfsStartDriver (
IN APFS_PRIVATE_DATA *PrivateData,
IN VOID *DriverBuffer,
IN UINT32 DriverSize
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
EFI_HANDLE ImageHandle;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_IMAGE_LOAD LoadImage;
APPLE_SECURE_BOOT_PROTOCOL *SecureBoot;
UINT8 Policy;
Status = PeCoffVerifyAppleSignature (
DriverBuffer,
&DriverSize
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
"OCJS: Failed to verify signature %g - %r\n",
&PrivateData->LocationInfo.ContainerUuid,
Status
));
return Status;
}
Status = ApfsVerifyDriverVersion (
PrivateData,
DriverBuffer,
DriverSize
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->HandleProtocol (
PrivateData->LocationInfo.ControllerHandle,
&gEfiDevicePathProtocolGuid,
(VOID **) &DevicePath
);
if (EFI_ERROR (Status)) {
DevicePath = NULL;
}
SecureBoot = OcAppleSecureBootGetProtocol ();
ASSERT (SecureBoot != NULL);
Status = SecureBoot->GetPolicy (
SecureBoot,
&Policy
);
//
// Load directly when we have Apple Secure Boot.
// - Either normal.
// - Or during DMG loading.
//
if ((!EFI_ERROR (Status) && Policy != AppleImg4SbModeDisabled)
|| (OcAppleSecureBootGetDmgLoading (&Policy) && Policy != AppleImg4SbModeDisabled)) {
LoadImage = OcImageLoaderLoad;
} else {
LoadImage = gBS->LoadImage;
}
ImageHandle = NULL;
Status = LoadImage (
FALSE,
gImageHandle,
DevicePath,
DriverBuffer,
DriverSize,
&ImageHandle
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
"OCJS: Failed to load %g - %r\n",
&PrivateData->LocationInfo.ContainerUuid,
Status
));
return Status;
}
//
// Disable verbose mode on request.
// Note, we cannot deallocate null text output table once we allocate it.
//
if (mIgnoreVerbose) {
Status = gBS->HandleProtocol (
ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID *) &LoadedImage
);
if (!EFI_ERROR (Status)) {
if (mNullSystemTable == NULL) {
mNullSystemTable = AllocateNullTextOutSystemTable (gST);
}
if (mNullSystemTable != NULL) {
LoadedImage->SystemTable = mNullSystemTable;
}
}
}
Status = gBS->StartImage (
ImageHandle,
NULL,
NULL
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
"OCJS: Failed to start %g - %r\n",
&PrivateData->LocationInfo.ContainerUuid,
Status
));
gBS->UnloadImage (ImageHandle);
return Status;
}
DEBUG ((
DEBUG_INFO,
"OCJS: Connecting %a%a APFS driver on handle %p\n",
mGlobalConnect ? "globally" : "normally",
mDisconnectHandles ? " with disconnection" : "",
PrivateData->LocationInfo.ControllerHandle
));
if (mDisconnectHandles) {
//
// Unblock handles as some types of firmware, such as that on the HP EliteBook 840 G2,
// may automatically lock all volumes without filesystem drivers upon
// any attempt to connect them.
// REF: https://github.com/acidanthera/bugtracker/issues/1128
//
OcDisconnectDriversOnHandle (PrivateData->LocationInfo.ControllerHandle);
}
if (mGlobalConnect) {
//
// Connect all devices when implicitly requested. This is a workaround
// for some older HP laptops, which for some reason fail to connect by both
// drive and partition handles.
// REF: https://github.com/acidanthera/bugtracker/issues/960
//
OcConnectDrivers ();
} else {
//
// Recursively connect controller to get apfs.efi loaded.
// We cannot use apfs.efi handle as it apparently creates new handles.
// This follows ApfsJumpStart driver implementation.
//
gBS->ConnectController (PrivateData->LocationInfo.ControllerHandle, NULL, NULL, TRUE);
}
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
ApfsConnectDevice (
IN EFI_HANDLE Handle,
IN EFI_BLOCK_IO_PROTOCOL *BlockIo
)
{
EFI_STATUS Status;
APFS_NX_SUPERBLOCK *SuperBlock;
APFS_PRIVATE_DATA *PrivateData;
VOID *DriverBuffer;
UINT32 DriverSize;
//
// This may still be not APFS but some other file system.
//
Status = InternalApfsReadSuperBlock (BlockIo, &SuperBlock);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_INFO, "OCJS: Got APFS super block for %g\n", &SuperBlock->Uuid));
//
// We no longer need super block once we register ourselves.
//
Status = ApfsRegisterPartition (Handle, BlockIo, SuperBlock, &PrivateData);
FreePool (SuperBlock);
if (EFI_ERROR (Status)) {
return Status;
}
//
// We cannot load drivers if we have no fusion drive pair as they are not
// guaranteed to be located on each drive.
//
if (!PrivateData->CanLoadDriver) {
return EFI_NOT_READY;
}
Status = InternalApfsReadDriver (PrivateData, &DriverSize, &DriverBuffer);
if (EFI_ERROR (Status)) {
return Status;
}
Status = ApfsStartDriver (PrivateData, DriverBuffer, DriverSize);
FreePool (DriverBuffer);
return Status;
}
VOID
OcApfsConfigure (
IN UINT64 MinVersion,
IN UINT32 MinDate,
IN UINT32 ScanPolicy,
IN BOOLEAN GlobalConnect,
IN BOOLEAN DisconnectHandles,
IN BOOLEAN IgnoreVerbose
)
{
//
// Translate special values like 0 and -1.
//
if (MinVersion == OC_APFS_VERSION_ANY) {
mApfsMinimalVersion = 0;
} else if (MinVersion == OC_APFS_VERSION_AUTO) {
mApfsMinimalVersion = OC_APFS_VERSION_DEFAULT;
} else {
mApfsMinimalVersion = MinVersion;
}
if (MinDate == OC_APFS_DATE_ANY) {
mApfsMinimalDate = 0;
} else if (MinDate == OC_APFS_DATE_AUTO) {
mApfsMinimalDate = OC_APFS_DATE_DEFAULT;
} else {
mApfsMinimalDate = MinDate;
}
mOcScanPolicy = ScanPolicy;
mIgnoreVerbose = IgnoreVerbose;
mGlobalConnect = GlobalConnect;
mDisconnectHandles = DisconnectHandles;
}
EFI_STATUS
OcApfsConnectHandle (
IN EFI_HANDLE Handle,
IN BOOLEAN VerifyPolicy
)
{
EFI_STATUS Status;
VOID *TempProtocol;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
//
// In the end of successful APFS or some other driver connection
// we have a filesystem driver.
// We have nothing to do if the device is already connected.
//
Status = gBS->HandleProtocol (
Handle,
&gEfiSimpleFileSystemProtocolGuid,
&TempProtocol
);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_VERBOSE, "OCJS: FS already connected\n"));
return EFI_ALREADY_STARTED;
}
//
// Obtain Block I/O.
// We do not need to care about 2nd revision, as apfs.efi does not use it.
//
Status = gBS->HandleProtocol (
Handle,
&gEfiBlockIoProtocolGuid,
(VOID **) &BlockIo
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, BlockIo error - %r\n", Status));
return EFI_UNSUPPORTED;
}
//
// Filter out handles:
// - Without media.
// - Which are not partitions (APFS containers).
// - Which have non-POT block size.
//
if (BlockIo->Media == NULL
|| !BlockIo->Media->LogicalPartition) {
return EFI_UNSUPPORTED;
}
if (BlockIo->Media->BlockSize == 0
|| (BlockIo->Media->BlockSize & (BlockIo->Media->BlockSize - 1)) != 0) {
DEBUG ((
DEBUG_INFO,
"OCJS: Cannot connect, BlockIo malformed: %d %u\n",
BlockIo->Media->LogicalPartition,
BlockIo->Media->BlockSize
));
return EFI_UNSUPPORTED;
}
//
// Filter out handles, which do not respect OpenCore policy.
//
if (VerifyPolicy) {
Status = ApfsCheckOpenCoreScanPolicy (Handle);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, Policy error - %r\n", Status));
return Status;
}
}
//
// If the handle is marked as unsupported, we should respect this.
// TODO: Install this protocol on failure (not in ApfsJumpStart)?
//
Status = gBS->HandleProtocol (
Handle,
&gApfsUnsupportedBdsProtocolGuid,
&TempProtocol
);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, unsupported BDS\n"));
return EFI_UNSUPPORTED;
}
//
// If we installed APFS EFI boot record, then this handle is already
// handled, though potentially not connected.
//
Status = gBS->HandleProtocol (
Handle,
&gApfsEfiBootRecordInfoProtocolGuid,
&TempProtocol
);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, already handled\n"));
return EFI_UNSUPPORTED;
}
//
// This is possibly APFS, try connecting.
//
return ApfsConnectDevice (Handle, BlockIo);
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/zsl588-OpenCorePkg.git
git@gitlife.ru:oschina-mirror/zsl588-OpenCorePkg.git
oschina-mirror
zsl588-OpenCorePkg
zsl588-OpenCorePkg
0.7.7