OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcApfsConnect.c
Go to the documentation of this file.
1
15#include "OcApfsInternal.h"
16#include <Library/BaseLib.h>
17#include <Library/BaseOverflowLib.h>
18#include <Library/DebugLib.h>
19#include <Library/MemoryAllocationLib.h>
20#include <Library/OcApfsLib.h>
26#include <Library/UefiBootServicesTableLib.h>
27#include <Library/UefiRuntimeServicesTableLib.h>
28#include <Guid/OcVariable.h>
30#include <Protocol/DevicePath.h>
31#include <Protocol/LoadedImage.h>
32#include <Protocol/SimpleFileSystem.h>
33
34LIST_ENTRY mApfsPrivateDataList = INITIALIZE_LIST_HEAD_VARIABLE (mApfsPrivateDataList);
37STATIC UINT32 mOcScanPolicy;
38STATIC BOOLEAN mIgnoreVerbose;
39STATIC BOOLEAN mGlobalConnect;
40STATIC BOOLEAN mDisconnectHandles;
41STATIC EFI_SYSTEM_TABLE *mNullSystemTable;
42
43//
44// There seems to exist a driver with a very large version, which is treated by
45// apfs kernel extension to have 0 version. Follow suit.
46//
47STATIC UINT64 mApfsBlacklistedVersions[] = {
48 4294966999999999999ULL
49};
50
51STATIC
52EFI_STATUS
54 IN EFI_HANDLE Handle
55 )
56{
57 UINT32 ScanPolicy;
58
59 //
60 // If filesystem limitations are set and APFS is not allowed,
61 // report failure.
62 //
65 {
66 return EFI_UNSUPPORTED;
67 }
68
69 //
70 // If device type locking is set and this device is not allowed,
71 // report failure.
72 //
74 ScanPolicy = OcGetDevicePolicyType (Handle, NULL);
75 if ((ScanPolicy & mOcScanPolicy) == 0) {
76 return EFI_UNSUPPORTED;
77 }
78 }
79
80 return EFI_SUCCESS;
81}
82
83STATIC
84EFI_STATUS
86 IN APFS_PRIVATE_DATA *PrivateData,
87 IN VOID *DriverBuffer,
88 IN UINT32 DriverSize
89 )
90{
91 EFI_STATUS Status;
92 APFS_DRIVER_VERSION *DriverVersion;
93 UINT64 RealVersion;
94 UINT32 RealDate;
95 UINTN Index;
96 BOOLEAN HasLegitVersion;
97
99 DriverBuffer,
100 DriverSize,
101 &DriverVersion
102 );
103 if (EFI_ERROR (Status)) {
104 DEBUG ((
105 DEBUG_WARN,
106 "OCJS: No APFS driver version found for %g - %r\n",
107 &PrivateData->LocationInfo.ContainerUuid,
108 Status
109 ));
110
111 RealVersion = 22;
112 RealDate = 0;
113 } else {
114 RealVersion = DriverVersion->Version;
115 RealDate = 0;
116
117 //
118 // Parse YYYY/MM/DD date.
119 //
120 for (Index = 0; Index < 10; ++Index) {
121 if (((Index == 4) || (Index == 7))) {
122 if (DriverVersion->Date[Index] != '/') {
123 RealDate = 0;
124 break;
125 }
126
127 continue;
128 }
129
130 if ((DriverVersion->Date[Index] < '0') || (DriverVersion->Date[Index] > '9')) {
131 RealDate = 0;
132 break;
133 }
134
135 RealDate *= 10;
136 RealDate += DriverVersion->Date[Index] - '0';
137 }
138
139 if (RealDate == 0) {
140 DEBUG ((
141 DEBUG_WARN,
142 "OCJS: APFS driver date is invalid for %g\n",
143 &PrivateData->LocationInfo.ContainerUuid
144 ));
145 }
146 }
147
148 for (Index = 0; Index < ARRAY_SIZE (mApfsBlacklistedVersions); ++Index) {
149 if (RealVersion == mApfsBlacklistedVersions[Index]) {
150 DEBUG ((
151 DEBUG_WARN,
152 "OCJS: APFS driver version %Lu is blacklisted for %g, treating as 0\n",
153 DriverVersion->Version,
154 &PrivateData->LocationInfo.ContainerUuid
155 ));
156 RealVersion = 0;
157 break;
158 }
159 }
160
161 HasLegitVersion = (mApfsMinimalVersion == 0 || mApfsMinimalVersion <= RealVersion)
162 && (mApfsMinimalDate == 0 || mApfsMinimalDate <= RealDate);
163
164 DEBUG ((
165 DEBUG_INFO,
166 "OCJS: APFS driver %Lu/%u found for %g, required >= %Lu/%u, %a\n",
167 RealVersion,
168 RealDate,
169 &PrivateData->LocationInfo.ContainerUuid,
172 HasLegitVersion ? "allow" : "prohibited"
173 ));
174
175 if (HasLegitVersion) {
176 return EFI_SUCCESS;
177 }
178
179 return EFI_SECURITY_VIOLATION;
180}
181
182STATIC
183EFI_STATUS
185 IN EFI_HANDLE Handle,
186 IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
187 IN APFS_NX_SUPERBLOCK *SuperBlock,
188 OUT APFS_PRIVATE_DATA **PrivateDataPointer
189 )
190{
191 EFI_STATUS Status;
192 APFS_PRIVATE_DATA *PrivateData;
193
194 PrivateData = AllocateZeroPool (sizeof (*PrivateData));
195 if (PrivateData == NULL) {
196 return EFI_OUT_OF_RESOURCES;
197 }
198
199 //
200 // File private data fields.
201 //
203 PrivateData->LocationInfo.ControllerHandle = Handle;
204 CopyGuid (&PrivateData->LocationInfo.ContainerUuid, &SuperBlock->Uuid);
205 PrivateData->BlockIo = BlockIo;
206 PrivateData->ApfsBlockSize = SuperBlock->BlockSize;
207 PrivateData->LbaMultiplier = PrivateData->ApfsBlockSize / PrivateData->BlockIo->Media->BlockSize;
208 PrivateData->EfiJumpStart = SuperBlock->EfiJumpStart;
209 InternalApfsInitFusionData (SuperBlock, PrivateData);
210
211 //
212 // Install boot record information.
213 // This guarantees us that we never register twice.
214 //
215 Status = gBS->InstallMultipleProtocolInterfaces (
216 &PrivateData->LocationInfo.ControllerHandle,
218 &PrivateData->LocationInfo,
219 NULL
220 );
221 if (EFI_ERROR (Status)) {
222 FreePool (PrivateData);
223 return Status;
224 }
225
226 //
227 // Save into the list and return.
228 //
229 InsertTailList (&mApfsPrivateDataList, &PrivateData->Link);
230 *PrivateDataPointer = PrivateData;
231 return EFI_SUCCESS;
232}
233
234STATIC
235EFI_STATUS
237 IN APFS_PRIVATE_DATA *PrivateData,
238 IN VOID *DriverBuffer,
239 IN UINT32 DriverSize
240 )
241{
242 EFI_STATUS Status;
243 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
244 EFI_HANDLE ImageHandle;
245 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
246
248 DriverBuffer,
249 &DriverSize
250 );
251 if (EFI_ERROR (Status)) {
252 DEBUG ((
253 DEBUG_INFO,
254 "OCJS: Failed to verify signature %g - %r\n",
255 &PrivateData->LocationInfo.ContainerUuid,
256 Status
257 ));
258 return Status;
259 }
260
261 Status = ApfsVerifyDriverVersion (
262 PrivateData,
263 DriverBuffer,
264 DriverSize
265 );
266 if (EFI_ERROR (Status)) {
267 return Status;
268 }
269
270 Status = gBS->HandleProtocol (
271 PrivateData->LocationInfo.ControllerHandle,
273 (VOID **)&DevicePath
274 );
275 if (EFI_ERROR (Status)) {
276 DevicePath = NULL;
277 }
278
279 //
280 // Always load jump started APFS directly - we cannot always successfully
281 // pass the sanitized image to OC-wrapped platform loader, because apfs.efi
282 // has W^X errors which require fixup for strict loaders, however the fact
283 // that apfs.efi instances are Apple signed images cannot be detected again
284 // after sanitisation (i.e. in ImageLoader.c in order to apply fixup before
285 // a strict - e.g. Duet - platform loader sees it).
286 //
287 ImageHandle = NULL;
288 Status = OcImageLoaderLoad (
289 FALSE,
291 DevicePath,
292 DriverBuffer,
293 DriverSize,
294 &ImageHandle
295 );
296 if (EFI_ERROR (Status)) {
297 DEBUG ((
298 DEBUG_INFO,
299 "OCJS: Failed to load %g - %r\n",
300 &PrivateData->LocationInfo.ContainerUuid,
301 Status
302 ));
303 return Status;
304 }
305
306 //
307 // Disable verbose mode on request.
308 // Note, we cannot deallocate null text output table once we allocate it.
309 //
310 if (mIgnoreVerbose) {
311 Status = gBS->HandleProtocol (
312 ImageHandle,
314 (VOID *)&LoadedImage
315 );
316 if (!EFI_ERROR (Status)) {
317 if (mNullSystemTable == NULL) {
319 }
320
321 if (mNullSystemTable != NULL) {
322 LoadedImage->SystemTable = mNullSystemTable;
323 }
324 }
325 }
326
327 Status = gBS->StartImage (
328 ImageHandle,
329 NULL,
330 NULL
331 );
332
333 if (EFI_ERROR (Status)) {
334 DEBUG ((
335 DEBUG_INFO,
336 "OCJS: Failed to start %g - %r\n",
337 &PrivateData->LocationInfo.ContainerUuid,
338 Status
339 ));
340
341 gBS->UnloadImage (ImageHandle);
342 return Status;
343 }
344
345 DEBUG ((
346 DEBUG_INFO,
347 "OCJS: Connecting %a%a APFS driver on handle %p\n",
348 mGlobalConnect ? "globally" : "normally",
349 mDisconnectHandles ? " with disconnection" : "",
350 PrivateData->LocationInfo.ControllerHandle
351 ));
352
353 if (mDisconnectHandles) {
354 //
355 // Unblock handles as some types of firmware, such as that on the HP EliteBook 840 G2,
356 // may automatically lock all volumes without filesystem drivers upon
357 // any attempt to connect them.
358 // REF: https://github.com/acidanthera/bugtracker/issues/1128
359 //
360 OcDisconnectDriversOnHandle (PrivateData->LocationInfo.ControllerHandle);
361 }
362
363 if (mGlobalConnect) {
364 //
365 // Connect all devices when implicitly requested. This is a workaround
366 // for some older HP laptops, which for some reason fail to connect by both
367 // drive and partition handles.
368 // REF: https://github.com/acidanthera/bugtracker/issues/960
369 //
371 } else {
372 //
373 // Recursively connect controller to get apfs.efi loaded.
374 // We cannot use apfs.efi handle as it apparently creates new handles.
375 // This follows ApfsJumpStart driver implementation.
376 //
377 gBS->ConnectController (PrivateData->LocationInfo.ControllerHandle, NULL, NULL, TRUE);
378 }
379
380 return EFI_SUCCESS;
381}
382
383STATIC
384EFI_STATUS
386 IN EFI_HANDLE Handle,
387 IN EFI_BLOCK_IO_PROTOCOL *BlockIo
388 )
389{
390 EFI_STATUS Status;
391 APFS_NX_SUPERBLOCK *SuperBlock;
392 APFS_PRIVATE_DATA *PrivateData;
393 VOID *DriverBuffer;
394 UINT32 DriverSize;
395
396 //
397 // This may still be not APFS but some other file system.
398 //
399 Status = InternalApfsReadSuperBlock (BlockIo, &SuperBlock);
400 if (EFI_ERROR (Status)) {
401 return Status;
402 }
403
404 DEBUG ((DEBUG_INFO, "OCJS: Got APFS super block for %g\n", &SuperBlock->Uuid));
405
406 //
407 // We no longer need super block once we register ourselves.
408 //
409 Status = ApfsRegisterPartition (Handle, BlockIo, SuperBlock, &PrivateData);
410 FreePool (SuperBlock);
411 if (EFI_ERROR (Status)) {
412 return Status;
413 }
414
415 //
416 // We cannot load drivers if we have no fusion drive pair as they are not
417 // guaranteed to be located on each drive.
418 //
419 if (!PrivateData->CanLoadDriver) {
420 return EFI_NOT_READY;
421 }
422
423 Status = InternalApfsReadDriver (PrivateData, &DriverSize, &DriverBuffer);
424 if (EFI_ERROR (Status)) {
425 return Status;
426 }
427
428 Status = ApfsStartDriver (PrivateData, DriverBuffer, DriverSize);
429 FreePool (DriverBuffer);
430 return Status;
431}
432
433VOID
435 IN UINT64 MinVersion,
436 IN UINT32 MinDate,
437 IN UINT32 ScanPolicy,
438 IN BOOLEAN GlobalConnect,
439 IN BOOLEAN DisconnectHandles,
440 IN BOOLEAN IgnoreVerbose
441 )
442{
443 //
444 // Translate special values like 0 and -1.
445 //
446 if (MinVersion == OC_APFS_VERSION_ANY) {
448 } else if (MinVersion == OC_APFS_VERSION_AUTO) {
450 } else {
451 mApfsMinimalVersion = MinVersion;
452 }
453
454 if (MinDate == OC_APFS_DATE_ANY) {
456 } else if (MinDate == OC_APFS_DATE_AUTO) {
458 } else {
459 mApfsMinimalDate = MinDate;
460 }
461
462 mOcScanPolicy = ScanPolicy;
463 mIgnoreVerbose = IgnoreVerbose;
464 mGlobalConnect = GlobalConnect;
465 mDisconnectHandles = DisconnectHandles;
466}
467
468EFI_STATUS
470 IN EFI_HANDLE Handle,
471 IN BOOLEAN VerifyPolicy
472 )
473{
474 EFI_STATUS Status;
475 VOID *TempProtocol;
476 EFI_BLOCK_IO_PROTOCOL *BlockIo;
477
478 //
479 // In the end of successful APFS or some other driver connection
480 // we have a filesystem driver.
481 // We have nothing to do if the device is already connected.
482 //
483 Status = gBS->HandleProtocol (
484 Handle,
486 &TempProtocol
487 );
488 if (!EFI_ERROR (Status)) {
489 DEBUG ((DEBUG_VERBOSE, "OCJS: FS already connected\n"));
490 return EFI_ALREADY_STARTED;
491 }
492
493 //
494 // Obtain Block I/O.
495 // We do not need to care about 2nd revision, as apfs.efi does not use it.
496 //
497 Status = gBS->HandleProtocol (
498 Handle,
500 (VOID **)&BlockIo
501 );
502 if (EFI_ERROR (Status)) {
503 DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, BlockIo error - %r\n", Status));
504 return EFI_UNSUPPORTED;
505 }
506
507 //
508 // Filter out handles:
509 // - Without media.
510 // - Which are not partitions (APFS containers).
511 // - Which have non-POT block size.
512 //
513 if ( (BlockIo->Media == NULL)
514 || !BlockIo->Media->LogicalPartition)
515 {
516 return EFI_UNSUPPORTED;
517 }
518
519 if ( (BlockIo->Media->BlockSize == 0)
520 || ((BlockIo->Media->BlockSize & (BlockIo->Media->BlockSize - 1)) != 0))
521 {
522 DEBUG ((
523 DEBUG_INFO,
524 "OCJS: Cannot connect, BlockIo malformed: %d %u\n",
525 BlockIo->Media->LogicalPartition,
526 BlockIo->Media->BlockSize
527 ));
528 return EFI_UNSUPPORTED;
529 }
530
531 //
532 // Filter out handles, which do not respect OpenCore policy.
533 //
534 if (VerifyPolicy) {
536 if (EFI_ERROR (Status)) {
537 DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, Policy error - %r\n", Status));
538 return Status;
539 }
540 }
541
542 //
543 // If the handle is marked as unsupported, we should respect this.
544 // TODO: Install this protocol on failure (not in ApfsJumpStart)?
545 //
546 Status = gBS->HandleProtocol (
547 Handle,
549 &TempProtocol
550 );
551 if (!EFI_ERROR (Status)) {
552 DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, unsupported BDS\n"));
553 return EFI_UNSUPPORTED;
554 }
555
556 //
557 // If we installed APFS EFI boot record, then this handle is already
558 // handled, though potentially not connected.
559 //
560 Status = gBS->HandleProtocol (
561 Handle,
563 &TempProtocol
564 );
565 if (!EFI_ERROR (Status)) {
566 DEBUG ((DEBUG_INFO, "OCJS: Cannot connect, already handled\n"));
567 return EFI_UNSUPPORTED;
568 }
569
570 //
571 // This is possibly APFS, try connecting.
572 //
573 return ApfsConnectDevice (Handle, BlockIo);
574}
EFI_GUID gApfsEfiBootRecordInfoProtocolGuid
EFI_GUID gApfsUnsupportedBdsProtocolGuid
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
STATIC UINT32 mOcScanPolicy
LIST_ENTRY mApfsPrivateDataList
STATIC EFI_STATUS ApfsCheckOpenCoreScanPolicy(IN EFI_HANDLE Handle)
EFI_STATUS OcApfsConnectHandle(IN EFI_HANDLE Handle, IN BOOLEAN VerifyPolicy)
STATIC UINT64 mApfsBlacklistedVersions[]
VOID OcApfsConfigure(IN UINT64 MinVersion, IN UINT32 MinDate, IN UINT32 ScanPolicy, IN BOOLEAN GlobalConnect, IN BOOLEAN DisconnectHandles, IN BOOLEAN IgnoreVerbose)
STATIC UINT32 mApfsMinimalDate
STATIC EFI_STATUS ApfsStartDriver(IN APFS_PRIVATE_DATA *PrivateData, IN VOID *DriverBuffer, IN UINT32 DriverSize)
STATIC BOOLEAN mGlobalConnect
STATIC EFI_STATUS ApfsVerifyDriverVersion(IN APFS_PRIVATE_DATA *PrivateData, IN VOID *DriverBuffer, IN UINT32 DriverSize)
STATIC BOOLEAN mDisconnectHandles
STATIC EFI_STATUS ApfsConnectDevice(IN EFI_HANDLE Handle, IN EFI_BLOCK_IO_PROTOCOL *BlockIo)
STATIC BOOLEAN mIgnoreVerbose
STATIC EFI_SYSTEM_TABLE * mNullSystemTable
STATIC UINT64 mApfsMinimalVersion
STATIC EFI_STATUS ApfsRegisterPartition(IN EFI_HANDLE Handle, IN EFI_BLOCK_IO_PROTOCOL *BlockIo, IN APFS_NX_SUPERBLOCK *SuperBlock, OUT APFS_PRIVATE_DATA **PrivateDataPointer)
VOID InternalApfsInitFusionData(IN APFS_NX_SUPERBLOCK *SuperBlock, OUT APFS_PRIVATE_DATA *PrivateData)
#define APFS_PRIVATE_DATA_SIGNATURE
EFI_STATUS InternalApfsReadDriver(IN APFS_PRIVATE_DATA *PrivateData, OUT UINT32 *DriverSize, OUT VOID **DriverBuffer)
Definition OcApfsIo.c:403
EFI_STATUS InternalApfsReadSuperBlock(IN EFI_BLOCK_IO_PROTOCOL *BlockIo, OUT APFS_NX_SUPERBLOCK **SuperBlockPtr)
Definition OcApfsIo.c:283
#define OC_APFS_VERSION_DEFAULT
Definition OcApfsLib.h:45
#define OC_APFS_VERSION_ANY
Definition OcApfsLib.h:57
#define OC_APFS_DATE_AUTO
Definition OcApfsLib.h:52
#define OC_APFS_DATE_ANY
Definition OcApfsLib.h:58
#define OC_APFS_VERSION_AUTO
Definition OcApfsLib.h:51
#define OC_APFS_DATE_DEFAULT
Definition OcApfsLib.h:46
#define OC_SCAN_DEVICE_LOCK
EFI_STATUS EFIAPI OcImageLoaderLoad(IN BOOLEAN BootPolicy, IN EFI_HANDLE ParentImageHandle, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN VOID *SourceBuffer OPTIONAL, IN UINTN SourceSize, OUT EFI_HANDLE *ImageHandle)
UINT32 OcGetDevicePolicyType(IN EFI_HANDLE Handle, OUT BOOLEAN *External OPTIONAL)
#define OC_SCAN_FILE_SYSTEM_LOCK
#define OC_SCAN_ALLOW_FS_APFS
EFI_SYSTEM_TABLE * gST
EFI_HANDLE gImageHandle
EFI_BOOT_SERVICES * gBS
EFI_SYSTEM_TABLE * AllocateNullTextOutSystemTable(IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS OcConnectDrivers(VOID)
EFI_STATUS OcDisconnectDriversOnHandle(IN EFI_HANDLE Controller)
EFI_STATUS PeCoffVerifyAppleSignature(IN OUT VOID *PeImage, IN OUT UINT32 *ImageSize)
EFI_STATUS PeCoffGetApfsDriverVersion(IN VOID *DriverBuffer, IN UINT32 DriverSize, OUT APFS_DRIVER_VERSION **DriverVersionPtr)
APPLE_EVENT_HANDLE Handle
Definition OcTypingLib.h:45
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
EFI_GUID gEfiSimpleFileSystemProtocolGuid
EFI_GUID gEfiBlockIoProtocolGuid
EFI_GUID gEfiLoadedImageProtocolGuid
EFI_GUID gEfiDevicePathProtocolGuid
CHAR8 Date[16]
Definition Apfs.h:116
EFI_GUID Uuid
Definition Apfs.h:216
APFS_EFIBOOTRECORD_LOCATION_INFO LocationInfo
EFI_BLOCK_IO_PROTOCOL * BlockIo