OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcApfsFusion.c
Go to the documentation of this file.
1
15#include "OcApfsInternal.h"
16#include <Library/BaseLib.h>
17#include <Library/BaseMemoryLib.h>
18#include <Library/DebugLib.h>
19#include <Library/MemoryAllocationLib.h>
20#include <Library/OcApfsLib.h>
21#include <Protocol/BlockIo.h>
22
23VOID
25 IN APFS_NX_SUPERBLOCK *SuperBlock,
26 OUT APFS_PRIVATE_DATA *PrivateData
27 )
28{
29 LIST_ENTRY *Entry;
30 APFS_PRIVATE_DATA *Sibling;
31 UINT32 BlockSize;
32
33 //
34 // All-zero Fusion UUID means this is a normal disk.
35 //
36 if (IsZeroGuid (&SuperBlock->FusionUuid)) {
37 PrivateData->CanLoadDriver = TRUE;
38 return;
39 }
40
41 CopyGuid (&PrivateData->FusionUuid, &SuperBlock->FusionUuid);
42 PrivateData->IsFusion = TRUE;
43
44 //
45 // According to the specification the highest bit is one for the
46 // Fusion set's main device and zero for the second-tier device.
47 //
48 // However, the actual implementation of ApfsJumpStart.efi is different
49 // from the specification. The specification says that the slave disk
50 // has the bits set, but the implementation seems to assume that for master.
51 //
52 PrivateData->IsFusionMaster = (SuperBlock->FusionUuid.Data4[7] & BIT0) == 0;
53 //
54 // Drop master type from the stored value for easier comparison.
55 //
56 PrivateData->FusionUuid.Data4[7] &= ~BIT0;
57
58 for (
59 Entry = GetFirstNode (&mApfsPrivateDataList);
60 !IsNull (&mApfsPrivateDataList, Entry);
61 Entry = GetNextNode (&mApfsPrivateDataList, Entry))
62 {
63 Sibling = CR (Entry, APFS_PRIVATE_DATA, Link, APFS_PRIVATE_DATA_SIGNATURE);
64
65 //
66 // Ignore the following potential siblings:
67 // - Non-fusion.
68 // - Ready to go fusion (aka FusionSibling != NULL).
69 // - Same master/slave type.
70 //
71 if ( !Sibling->IsFusion
72 || Sibling->CanLoadDriver
73 || (Sibling->IsFusionMaster == PrivateData->IsFusionMaster)
74 || !CompareGuid (&Sibling->FusionUuid, &PrivateData->FusionUuid))
75 {
76 continue;
77 }
78
79 //
80 // We have a matching fusion sibling, mark this partition as ready to go.
81 //
82 PrivateData->FusionSibling = Sibling;
83 PrivateData->CanLoadDriver = TRUE;
84 //
85 // Calculate FusionMask. This is essentially ctz, but we do not have it in EDK II.
86 // We cannot use division either, since ApfsBlockSize is not guaranteed to be POT.
87 //
88 PrivateData->FusionMask = APFS_FUSION_TIER2_DEVICE_BYTE_ADDR;
89 BlockSize = PrivateData->ApfsBlockSize;
90 while ((BlockSize & BIT0) == 0) {
91 PrivateData->FusionMask >>= 1U;
92 BlockSize >>= 1U;
93 }
94
95 //
96 // Update sibling fields as well.
97 //
98 PrivateData->FusionSibling->FusionSibling = PrivateData;
99 PrivateData->FusionSibling->CanLoadDriver = TRUE;
100 PrivateData->FusionSibling->FusionMask = PrivateData->FusionMask;
101 break;
102 }
103}
104
105EFI_BLOCK_IO_PROTOCOL *
107 IN APFS_PRIVATE_DATA *PrivateData,
108 IN UINT64 Block,
109 OUT EFI_LBA *Lba
110 )
111{
112 BOOLEAN IsFusionMaster;
113
114 ASSERT (PrivateData->CanLoadDriver);
115
116 //
117 // Note, LBA arithmetics may wrap around, but in this case we will
118 // just read the wrong block, and the signature is checked anyway.
119 //
120
121 //
122 // For normal disks we just return as is.
123 //
124 if (!PrivateData->IsFusion) {
125 *Lba = Block * PrivateData->LbaMultiplier;
126 return PrivateData->BlockIo;
127 }
128
129 ASSERT (PrivateData->FusionSibling != NULL);
130
131 //
132 // For Fusion disks it can be either volume.
133 //
134 if ((Block & PrivateData->FusionMask) == 0) {
135 IsFusionMaster = TRUE;
136 } else {
137 Block &= ~PrivateData->FusionMask;
138 IsFusionMaster = FALSE;
139 }
140
141 *Lba = Block * PrivateData->LbaMultiplier;
142
143 if (IsFusionMaster == PrivateData->IsFusionMaster) {
144 return PrivateData->BlockIo;
145 }
146
147 return PrivateData->FusionSibling->BlockIo;
148}
#define APFS_FUSION_TIER2_DEVICE_BYTE_ADDR
Definition Apfs.h:88
UINT16 BlockSize
Definition Apm.h:32
LIST_ENTRY mApfsPrivateDataList
EFI_BLOCK_IO_PROTOCOL * InternalApfsTranslateBlock(IN APFS_PRIVATE_DATA *PrivateData, IN UINT64 Block, OUT EFI_LBA *Lba)
VOID InternalApfsInitFusionData(IN APFS_NX_SUPERBLOCK *SuperBlock, OUT APFS_PRIVATE_DATA *PrivateData)
#define APFS_PRIVATE_DATA_SIGNATURE
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
BOOLEAN EFIAPI IsZeroGuid(IN CONST GUID *Guid)
#define ASSERT(x)
Definition coder.h:55