OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
LegacyBootSupport.c
Go to the documentation of this file.
1
7
8THUNK_CONTEXT mThunkContext;
9
10//
11// PIWG firmware media device path for Apple legacy interface.
12// FwFile(2B0585EB-D8B8-49A9-8B8CE21B01AEF2B7)
13//
15 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
16 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
17 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00
18};
19STATIC CONST EFI_DEVICE_PATH_PROTOCOL *AppleLegacyInterfaceMediaDevicePathPath = (EFI_DEVICE_PATH_PROTOCOL *)AppleLegacyInterfaceMediaDevicePathData;
20
21#define MAX_APPLE_LEGACY_DEVICE_PATHS 16
22
23STATIC
24BOOLEAN
26 IN CONST CHAR8 *SignatureStr,
27 IN UINT8 *Buffer,
28 IN UINTN BufferSize
29 )
30{
31 UINT32 Offset;
32
33 Offset = 0;
34
35 return FindPattern (
36 (CONST UINT8 *)SignatureStr,
37 NULL,
38 (CONST UINT32)AsciiStrLen (SignatureStr),
39 Buffer,
40 (UINT32)BufferSize,
41 &Offset
42 );
43}
44
45STATIC
46EFI_STATUS
48 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePaths,
49 IN UINTN MaxDevicePaths
50 )
51{
52 EFI_STATUS Status;
53 UINTN NoHandles;
54 EFI_HANDLE *Handles;
55 UINTN HandleIndex;
56 UINTN PathCount;
57 UINTN PathIndex;
58 BOOLEAN DevicePathExists;
59
60 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
61 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
62
63 MaxDevicePaths--;
64 PathCount = 0;
65
66 //
67 // Get all LoadedImage protocol handles.
68 //
69 Status = gBS->LocateHandleBuffer (
70 ByProtocol,
72 NULL,
73 &NoHandles,
74 &Handles
75 );
76 if (EFI_ERROR (Status)) {
77 return Status;
78 }
79
80 for (HandleIndex = 0; HandleIndex < NoHandles && PathCount < MaxDevicePaths; HandleIndex++) {
81 Status = gBS->HandleProtocol (
82 Handles[HandleIndex],
84 (VOID **)&LoadedImage
85 );
86 if (EFI_ERROR (Status)) {
87 continue;
88 }
89
90 Status = gBS->HandleProtocol (
91 LoadedImage->DeviceHandle,
93 (VOID **)&DevicePath
94 );
95 if (EFI_ERROR (Status)) {
96 continue;
97 }
98
99 //
100 // Legacy boot interface will be behind a memory range node.
101 //
102 if ( (DevicePathType (DevicePath) != HARDWARE_DEVICE_PATH)
103 || (DevicePathSubType (DevicePath) != HW_MEMMAP_DP))
104 {
105 continue;
106 }
107
108 //
109 // Ensure we don't add a duplicate path.
110 //
111 DevicePathExists = FALSE;
112 for (PathIndex = 0; PathIndex < PathCount; PathIndex++) {
113 if (DevicePathNodeLength (DevicePath) != DevicePathNodeLength (DevicePaths[PathIndex])) {
114 continue;
115 }
116
117 if (CompareMem (DevicePath, DevicePaths[PathIndex], DevicePathNodeLength (DevicePath))) {
118 DevicePathExists = TRUE;
119 break;
120 }
121 }
122
123 if (DevicePathExists) {
124 continue;
125 }
126
127 DevicePaths[PathCount++] = AppendDevicePath (DevicePath, AppleLegacyInterfaceMediaDevicePathPath);
128 }
129
130 FreePool (Handles);
131
132 DevicePaths[PathCount] = NULL;
133 return EFI_SUCCESS;
134}
135
136EFI_STATUS
138 OUT BOOLEAN *IsAppleInterfaceSupported
139 )
140{
141 EFI_STATUS Status;
142 EFI_LEGACY_8259_PROTOCOL *Legacy8259;
143
144 ASSERT (IsAppleInterfaceSupported != NULL);
145
146 //
147 // Apple legacy boot interface is only available on Apple platforms.
148 // Use legacy 16-bit thunks on legacy PC platforms.
149 //
150 if (OcStriCmp (L"Apple", gST->FirmwareVendor) == 0) {
151 *IsAppleInterfaceSupported = TRUE;
152 return EFI_SUCCESS;
153 } else {
154 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&Legacy8259);
155 if (!EFI_ERROR (Status) && (Legacy8259 != NULL)) {
156 *IsAppleInterfaceSupported = FALSE;
157 return EFI_SUCCESS;
158 }
159 }
160
161 return EFI_UNSUPPORTED;
162}
163
164EFI_STATUS
166 IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath
167 )
168{
169 EFI_STATUS Status;
170 EFI_HANDLE DiskHandle;
171 EFI_HANDLE PartitionHandle;
172 UINT8 PartitionIndex;
173 EFI_DEVICE_PATH_PROTOCOL *WholeDiskPath;
174
175 WholeDiskPath = OcDiskGetDevicePath (HdDevicePath);
176 if (WholeDiskPath == NULL) {
177 return EFI_INVALID_PARAMETER;
178 }
179
180 DebugPrintDevicePath (DEBUG_INFO, "OLB: Legacy disk device path", WholeDiskPath);
181
182 //
183 // Mark target partition as active.
184 //
185 DiskHandle = OcPartitionGetDiskHandle (HdDevicePath);
186 if (DiskHandle == NULL) {
187 return EFI_INVALID_PARAMETER;
188 }
189
190 PartitionHandle = OcPartitionGetPartitionHandle (HdDevicePath);
191 if (PartitionHandle == NULL) {
192 return EFI_INVALID_PARAMETER;
193 }
194
195 Status = OcDiskGetMbrPartitionIndex (PartitionHandle, &PartitionIndex);
196 if (EFI_ERROR (Status)) {
197 return Status;
198 }
199
200 Status = OcDiskMarkMbrPartitionActive (DiskHandle, PartitionIndex);
201 if (EFI_ERROR (Status)) {
202 return Status;
203 }
204
205 //
206 // Set BootCampHD variable pointing to target disk.
207 //
208 return gRT->SetVariable (
211 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
212 GetDevicePathSize (WholeDiskPath),
213 WholeDiskPath
214 );
215}
216
217EFI_STATUS
219 IN EFI_HANDLE ParentImageHandle,
220 OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,
221 OUT EFI_HANDLE *ImageHandle
222 )
223{
224 EFI_STATUS Status;
225 EFI_DEVICE_PATH_PROTOCOL **LegacyDevicePaths;
226 CHAR16 *UnicodeDevicePath;
227 UINTN Index;
228
229 //
230 // Get list of possible locations for Apple legacy interface and attempt to load.
231 //
232 LegacyDevicePaths = AllocateZeroPool (sizeof (*LegacyDevicePaths) * MAX_APPLE_LEGACY_DEVICE_PATHS);
233 if (LegacyDevicePaths == NULL) {
234 return EFI_OUT_OF_RESOURCES;
235 }
236
238 if (!EFI_ERROR (Status)) {
239 for (Index = 0; LegacyDevicePaths[Index] != NULL; Index++) {
240 Status = gBS->LoadImage (
241 FALSE,
242 ParentImageHandle,
243 LegacyDevicePaths[Index],
244 NULL,
245 0,
246 ImageHandle
247 );
248 if (Status != EFI_NOT_FOUND) {
249 *ImageDevicePath = LegacyDevicePaths[Index];
250
251 DEBUG_CODE_BEGIN ();
252
253 UnicodeDevicePath = ConvertDevicePathToText (*ImageDevicePath, FALSE, FALSE);
254 DEBUG ((
255 DEBUG_INFO,
256 "OLB: Loaded Apple legacy interface at dp %s - %r\n",
257 UnicodeDevicePath != NULL ? UnicodeDevicePath : L"<null>",
258 Status
259 ));
260 if (UnicodeDevicePath != NULL) {
261 FreePool (UnicodeDevicePath);
262 }
263
264 DEBUG_CODE_END ();
265
266 break;
267 }
268 }
269 }
270
271 FreePool (LegacyDevicePaths);
272
273 return Status;
274}
275
278 IN EFI_HANDLE PartitionHandle,
279 IN BOOLEAN IsCdRomSupported
280 )
281{
282 EFI_STATUS Status;
283 UINT8 *Buffer;
284 UINTN BufferSize;
285 MASTER_BOOT_RECORD *Mbr;
286 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
287 EFI_HANDLE DiskHandle;
288 OC_LEGACY_OS_TYPE LegacyOsType;
289
290 ASSERT (PartitionHandle != NULL);
291
292 DevicePath = DevicePathFromHandle (PartitionHandle);
293 if (DevicePath == NULL) {
294 return OcLegacyOsTypeNone;
295 }
296
297 DiskHandle = OcPartitionGetDiskHandle (DevicePath);
298 if (DiskHandle == NULL) {
299 return OcLegacyOsTypeNone;
300 }
301
302 //
303 // For CD devices, validate El-Torito structures.
304 // For hard disk and USB devices, validate MBR and PBR of target partition.
305 //
306 if (OcIsDiskCdRom (DevicePath)) {
307 if (!IsCdRomSupported) {
308 DEBUG ((DEBUG_INFO, "OLB: CD-ROM boot not supported on this platform\n"));
309 return OcLegacyOsTypeNone;
310 }
311
312 DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading El-Torito for CDROM", DevicePath);
313 Status = OcDiskReadElTorito (DevicePath, &Buffer, &BufferSize);
314 if (EFI_ERROR (Status)) {
315 DEBUG ((DEBUG_INFO, "OLB: Failed reading El-Torito - %r\n", Status));
316 return OcLegacyOsTypeNone;
317 }
318 } else {
319 DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading MBR for parent disk", DevicePath);
320 Mbr = OcGetDiskMbrTable (DiskHandle, TRUE);
321 if (Mbr == NULL) {
322 DEBUG ((DEBUG_INFO, "OLB: Disk does not contain a valid MBR\n"));
323 return OcLegacyOsTypeNone;
324 }
325
326 FreePool (Mbr);
327
328 //
329 // Retrieve PBR for partition.
330 //
331 DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading PBR for partition", DevicePath);
332 Mbr = OcGetDiskMbrTable (PartitionHandle, FALSE);
333 if (Mbr == NULL) {
334 DEBUG ((DEBUG_INFO, "OLB: Partition does not contain a valid PBR\n"));
335 return OcLegacyOsTypeNone;
336 }
337
338 Buffer = (UINT8 *)Mbr;
339 BufferSize = sizeof (*Mbr);
340 }
341
342 DebugPrintHexDump (DEBUG_INFO, "OLB: PbrHEX", Buffer, BufferSize);
343
344 //
345 // Validate sector contents and check for known signatures
346 // indicating the partition is bootable.
347 //
348 if (CheckLegacySignature ("BOOTMGR", Buffer, BufferSize)) {
349 LegacyOsType = OcLegacyOsTypeWindowsBootmgr;
350 } else if (CheckLegacySignature ("NTLDR", Buffer, BufferSize)) {
351 LegacyOsType = OcLegacyOsTypeWindowsNtldr;
352 } else if ( CheckLegacySignature ("ISOLINUX", Buffer, BufferSize)
353 || CheckLegacySignature ("isolinux", Buffer, BufferSize))
354 {
355 LegacyOsType = OcLegacyOsTypeIsoLinux;
356 } else {
357 LegacyOsType = OcLegacyOsTypeNone;
358 DEBUG ((DEBUG_INFO, "OLB: Unknown legacy bootsector signature\n"));
359 }
360
361 FreePool (Buffer);
362
363 return LegacyOsType;
364}
365
366EFI_STATUS
368 IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath
369 )
370{
371 EFI_STATUS Status;
372 EFI_HANDLE DiskHandle;
373 EFI_HANDLE PartitionHandle;
374 MASTER_BOOT_RECORD *Mbr;
375 MASTER_BOOT_RECORD *Pbr;
376 UINT8 PartitionIndex;
377 UINT8 BiosDiskAddress;
378
379 IA32_REGISTER_SET Regs;
380 MASTER_BOOT_RECORD *MbrPtr = (MASTER_BOOT_RECORD *)0x0600;
381 MASTER_BOOT_RECORD *PbrPtr = (MASTER_BOOT_RECORD *)0x7C00;
382 EFI_LEGACY_8259_PROTOCOL *Legacy8259;
383
384 //
385 // Locate Legacy8259 protocol.
386 //
387 Status = gBS->LocateProtocol (
389 NULL,
390 (VOID **)&Legacy8259
391 );
392 if (EFI_ERROR (Status)) {
393 DEBUG ((DEBUG_INFO, "OLB: Could not locate Legacy8259 protocol\n"));
394 return Status;
395 }
396
397 //
398 // Retrieve the PBR from partition and partition index.
399 //
400 PartitionHandle = OcPartitionGetPartitionHandle (PartitionPath);
401 if (PartitionHandle == NULL) {
402 DEBUG ((DEBUG_INFO, "OLB: Could not locate partition handle\n"));
403 return EFI_INVALID_PARAMETER;
404 }
405
406 Pbr = OcGetDiskMbrTable (PartitionHandle, FALSE);
407 if (Pbr == NULL) {
408 DEBUG ((DEBUG_INFO, "OLB: Partition does not contain a valid PBR\n"));
409 return EFI_INVALID_PARAMETER;
410 }
411
412 Status = OcDiskGetMbrPartitionIndex (PartitionHandle, &PartitionIndex);
413 if (EFI_ERROR (Status)) {
414 FreePool (Pbr);
415 return Status;
416 }
417
418 DebugPrintHexDump (DEBUG_INFO, "OLB: PbrHEX", (UINT8 *)Pbr, sizeof (*Pbr));
419
420 //
421 // Retrieve MBR from disk.
422 //
423 DiskHandle = OcPartitionGetDiskHandle (PartitionPath);
424 if (DiskHandle == NULL) {
425 FreePool (Pbr);
426 return EFI_INVALID_PARAMETER;
427 }
428
429 Mbr = OcGetDiskMbrTable (DiskHandle, TRUE);
430 if (Mbr == NULL) {
431 DEBUG ((DEBUG_INFO, "OLB: Disk does not contain a valid MBR\n"));
432 FreePool (Pbr);
433 return EFI_INVALID_PARAMETER;
434 }
435
436 DebugPrintHexDump (DEBUG_INFO, "OLB: MbrHEX", (UINT8 *)Mbr, sizeof (*Mbr));
437
438 //
439 // Create and initialize thunk structures.
440 //
442 if (EFI_ERROR (Status)) {
443 FreePool (Pbr);
444 FreePool (Mbr);
445 return Status;
446 }
447
449 if (EFI_ERROR (Status)) {
450 FreePool (Pbr);
451 FreePool (Mbr);
452 return Status;
453 }
454
455 //
456 // Determine BIOS disk number.
457 //
460 Legacy8259,
461 DiskHandle,
462 &BiosDiskAddress
463 );
464 if (EFI_ERROR (Status)) {
465 DEBUG ((DEBUG_INFO, "OLB: Disk address could not be determined\n"));
466 FreePool (Pbr);
467 FreePool (Mbr);
468 return Status;
469 }
470
471 //
472 // Copy MBR and PBR to low memory locations for booting.
473 //
474 CopyMem (PbrPtr, Pbr, sizeof (*Pbr));
475 CopyMem (MbrPtr, Mbr, sizeof (*Mbr));
476
477 DebugPrintHexDump (DEBUG_INFO, "OLB: PbrPtr", (UINT8 *)PbrPtr, sizeof (*PbrPtr));
478
480
481 //
482 // Thunk to real mode and invoke legacy boot sector.
483 // If successful, this function will not return.
484 //
485 ZeroMem (&Regs, sizeof (Regs));
486
487 Regs.H.DL = BiosDiskAddress;
488 Regs.X.SI = (UINT16)(UINTN)&MbrPtr->Partition[PartitionIndex];
491 Legacy8259,
492 0,
493 0x7c00,
494 &Regs,
495 NULL,
496 0
497 );
498
499 DEBUG ((DEBUG_WARN, "OLB: Failure calling legacy boot sector\n"));
500
501 return EFI_INVALID_PARAMETER;
502}
EFI_GUID gAppleBootVariableGuid
#define APPLE_BOOT_CAMP_HD_VARIABLE_NAME
EFI_STATUS InternalGetBiosDiskAddress(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN EFI_HANDLE DiskHandle, OUT UINT8 *DriveAddress)
Definition BiosDisk.c:140
EFI_GUID gEfiLegacy8259ProtocolGuid
@ OcLegacyOsTypeWindowsNtldr
@ OcLegacyOsTypeNone
@ OcLegacyOsTypeWindowsBootmgr
@ OcLegacyOsTypeIsoLinux
enum OC_LEGACY_OS_TYPE_ OC_LEGACY_OS_TYPE
EFI_STATUS InternalLoadAppleLegacyInterface(IN EFI_HANDLE ParentImageHandle, OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath, OUT EFI_HANDLE *ImageHandle)
#define MAX_APPLE_LEGACY_DEVICE_PATHS
OC_LEGACY_OS_TYPE InternalGetPartitionLegacyOsType(IN EFI_HANDLE PartitionHandle, IN BOOLEAN IsCdRomSupported)
EFI_STATUS InternalSetBootCampHDPath(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
EFI_STATUS InternalLoadLegacyPbr(IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath)
STATIC EFI_STATUS ScanAppleLegacyInterfacePaths(IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePaths, IN UINTN MaxDevicePaths)
STATIC CONST UINT8 AppleLegacyInterfaceMediaDevicePathData[]
STATIC BOOLEAN CheckLegacySignature(IN CONST CHAR8 *SignatureStr, IN UINT8 *Buffer, IN UINTN BufferSize)
THUNK_CONTEXT mThunkContext
EFI_STATUS InternalIsLegacyInterfaceSupported(OUT BOOLEAN *IsAppleInterfaceSupported)
STATIC CONST EFI_DEVICE_PATH_PROTOCOL * AppleLegacyInterfaceMediaDevicePathPath
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
VOID DebugPrintHexDump(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN UINT8 *Bytes, IN UINTN Size)
VOID DebugPrintDevicePath(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL)
EFI_HANDLE OcPartitionGetPartitionHandle(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:353
EFI_STATUS OcDiskGetMbrPartitionIndex(IN EFI_HANDLE PartitionHandle, OUT UINT8 *PartitionIndex)
Definition DiskMisc.c:908
EFI_HANDLE OcPartitionGetDiskHandle(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:331
EFI_DEVICE_PATH_PROTOCOL * OcDiskGetDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath)
Definition DiskMisc.c:280
EFI_STATUS OcDiskReadElTorito(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINT8 **Buffer, OUT UINTN *BufferSize)
Definition DiskMisc.c:392
BOOLEAN OcIsDiskCdRom(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath)
Definition DiskMisc.c:369
MASTER_BOOT_RECORD * OcGetDiskMbrTable(IN EFI_HANDLE DiskHandle, IN BOOLEAN CheckPartitions)
Definition DiskMisc.c:828
EFI_STATUS OcDiskMarkMbrPartitionActive(IN EFI_HANDLE DiskHandle, IN UINT8 PartitionIndex)
Definition DiskMisc.c:978
EFI_STATUS OcLegacyThunkInitializeInterruptRedirection(IN EFI_LEGACY_8259_PROTOCOL *Legacy8259)
BOOLEAN EFIAPI OcLegacyThunkFarCall86(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT16 Segment, IN UINT16 Offset, IN IA32_REGISTER_SET *Regs, IN VOID *Stack, IN UINTN StackSize)
EFI_STATUS OcLegacyThunkInitializeBiosIntCaller(IN OUT THUNK_CONTEXT *ThunkContext)
VOID OcLegacyThunkDisconnectEfiGraphics(VOID)
BOOLEAN FindPattern(IN CONST UINT8 *Pattern, IN CONST UINT8 *PatternMask OPTIONAL, IN CONST UINT32 PatternSize, IN CONST UINT8 *Data, IN UINT32 DataSize, IN OUT UINT32 *DataOff)
Definition DataPatcher.c:82
INTN EFIAPI OcStriCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString)
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
EFI_GUID gEfiLoadedImageProtocolGuid
EFI_GUID gEfiDevicePathProtocolGuid
EFI_DEVICE_PATH_PROTOCOL *EFIAPI DevicePathFromHandle(IN EFI_HANDLE Handle)
Definition UserMisc.c:680
#define ASSERT(x)
Definition coder.h:55