ea96ca11b23e9992b0d8581a62b869c0e06547d4
[reactos.git] / reactos / boot / environ / lib / firmware / efi / firmware.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/firmware/efi/firmware.c
5 * PURPOSE: Boot Library Firmware Initialization for EFI
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 PBL_FIRMWARE_DESCRIPTOR EfiFirmwareParameters;
16 BL_FIRMWARE_DESCRIPTOR EfiFirmwareData;
17 EFI_HANDLE EfiImageHandle;
18 EFI_SYSTEM_TABLE* EfiSystemTable;
19
20 EFI_SYSTEM_TABLE *EfiST;
21 EFI_BOOT_SERVICES *EfiBS;
22 EFI_RUNTIME_SERVICES *EfiRT;
23 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *EfiConOut;
24 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *EfiConIn;
25 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *EfiConInEx;
26 PHYSICAL_ADDRESS EfiRsdt;
27
28 EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
29 EFI_GUID EfiUgaDrawProtocol = EFI_UGA_DRAW_PROTOCOL_GUID;
30 EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
31 EFI_GUID EfiDevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID;
32 EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
33 EFI_GUID EfiBlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID;
34 EFI_GUID EfiRootAcpiTableGuid = EFI_ACPI_20_TABLE_GUID;
35 EFI_GUID EfiRootAcpiTable10Guid = EFI_ACPI_TABLE_GUID;
36 EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
37 EFI_GUID BlpEfiSecureBootPrivateNamespace = { 0x77FA9ABD , 0x0359, 0x4D32, { 0xBD, 0x60, 0x28, 0xF4, 0xE7, 0x8F, 0x78, 0x4B } };
38
39 WCHAR BlScratchBuffer[8192];
40
41 BOOLEAN BlpFirmwareChecked;
42 BOOLEAN BlpFirmwareEnabled;
43
44 /* FUNCTIONS *****************************************************************/
45
46 EFI_DEVICE_PATH *
47 EfiIsDevicePathParent (
48 _In_ EFI_DEVICE_PATH *DevicePath1,
49 _In_ EFI_DEVICE_PATH *DevicePath2
50 )
51 {
52 EFI_DEVICE_PATH* CurrentPath1;
53 EFI_DEVICE_PATH* CurrentPath2;
54 USHORT Length1, Length2;
55
56 /* Start with the current nodes */
57 CurrentPath1 = DevicePath1;
58 CurrentPath2 = DevicePath2;
59
60 /* Loop each element of the device path */
61 while (!(IsDevicePathEndType(CurrentPath1)) &&
62 !(IsDevicePathEndType(CurrentPath2)))
63 {
64 /* Check if the element has a different length */
65 Length1 = DevicePathNodeLength(CurrentPath1);
66 Length2 = DevicePathNodeLength(CurrentPath2);
67 if (Length1 != Length2)
68 {
69 /* Then they're not related */
70 return NULL;
71 }
72
73 /* Check if the rest of the element data matches */
74 if (RtlCompareMemory(CurrentPath1, CurrentPath2, Length1) != Length1)
75 {
76 /* Nope, not related */
77 return NULL;
78 }
79
80 /* Move to the next element */
81 CurrentPath1 = NextDevicePathNode(CurrentPath1);
82 CurrentPath2 = NextDevicePathNode(CurrentPath2);
83 }
84
85 /* If the last element in path 1 is empty, then path 2 is the child (deeper) */
86 if (!IsDevicePathEndType(CurrentPath1))
87 {
88 return DevicePath2;
89 }
90
91 /* If the last element in path 2 is empty, then path 1 is the child (deeper) */
92 if (!IsDevicePathEndType(CurrentPath2))
93 {
94 return DevicePath1;
95 }
96
97 /* They're both the end, so they're identical, so there's no parent */
98 return NULL;
99 }
100
101 EFI_DEVICE_PATH*
102 EfiGetLeafNode (
103 _In_ EFI_DEVICE_PATH *DevicePath
104 )
105 {
106 EFI_DEVICE_PATH *NextDevicePath;
107
108 /* Make sure we're not already at the end */
109 if (!IsDevicePathEndType(DevicePath))
110 {
111 /* Grab the next node element, and keep going until the end */
112 for (NextDevicePath = NextDevicePathNode(DevicePath);
113 !IsDevicePathEndType(NextDevicePath);
114 NextDevicePath = NextDevicePathNode(NextDevicePath))
115 {
116 /* Save the current node we're at */
117 DevicePath = NextDevicePath;
118 }
119 }
120
121 /* This now contains the deepest (leaf) node */
122 return DevicePath;
123 }
124
125 VOID
126 EfiPrintf (
127 _In_ PWCHAR Format,
128 ...
129 )
130 {
131 va_list args;
132 va_start(args, Format);
133
134 /* Capture the buffer in our scratch pad, and NULL-terminate */
135 vsnwprintf(BlScratchBuffer, RTL_NUMBER_OF(BlScratchBuffer) - 1, Format, args);
136 BlScratchBuffer[RTL_NUMBER_OF(BlScratchBuffer) - 1] = UNICODE_NULL;
137
138 /* Check which mode we're in */
139 if (CurrentExecutionContext->Mode == BlRealMode)
140 {
141 /* Call EFI directly */
142 EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
143 }
144 else
145 {
146 /* FIXME: @TODO: Not yet supported */
147 // FIXME: Hack while we are in early rosload mode
148 if (EfiConOut != NULL)
149 {
150 EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
151 }
152 }
153
154 /* All done */
155 va_end(args);
156 }
157
158 NTSTATUS
159 EfiOpenProtocol (
160 _In_ EFI_HANDLE Handle,
161 _In_ EFI_GUID *Protocol,
162 _Out_ PVOID* Interface
163 )
164 {
165 EFI_STATUS EfiStatus;
166 NTSTATUS Status;
167 BL_ARCH_MODE OldMode;
168
169 /* Are we using virtual memory/ */
170 if (MmTranslationType != BlNone)
171 {
172 /* We need complex tracking to make this work */
173 //Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
174 Status = STATUS_NOT_SUPPORTED;
175 }
176 else
177 {
178 /* Are we in protected mode? */
179 OldMode = CurrentExecutionContext->Mode;
180 if (OldMode != BlRealMode)
181 {
182 /* FIXME: Not yet implemented */
183 return STATUS_NOT_IMPLEMENTED;
184 }
185
186 /* Are we on legacy 1.02? */
187 if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
188 {
189 /* Make the legacy call */
190 EfiStatus = EfiBS->HandleProtocol(Handle, Protocol, Interface);
191 }
192 else
193 {
194 /* Use the UEFI version */
195 EfiStatus = EfiBS->OpenProtocol(Handle,
196 Protocol,
197 Interface,
198 EfiImageHandle,
199 NULL,
200 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
201
202 /* Switch back to protected mode if we came from there */
203 if (OldMode != BlRealMode)
204 {
205 BlpArchSwitchContext(OldMode);
206 }
207 }
208
209 /* Convert the error to an NTSTATUS */
210 Status = EfiGetNtStatusCode(EfiStatus);
211 }
212
213 /* Clear the interface on failure, and return the status */
214 if (!NT_SUCCESS(Status))
215 {
216 *Interface = NULL;
217 }
218
219 return Status;
220 }
221
222 NTSTATUS
223 EfiCloseProtocol (
224 _In_ EFI_HANDLE Handle,
225 _In_ EFI_GUID *Protocol
226 )
227 {
228 EFI_STATUS EfiStatus;
229 NTSTATUS Status;
230 BL_ARCH_MODE OldMode;
231
232 /* Are we using virtual memory/ */
233 if (MmTranslationType != BlNone)
234 {
235 /* We need complex tracking to make this work */
236 //Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
237 Status = STATUS_NOT_SUPPORTED;
238 }
239 else
240 {
241 /* Are we on legacy 1.02? */
242 if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
243 {
244 /* Nothing to close */
245 EfiStatus = STATUS_SUCCESS;
246 }
247 else
248 {
249 /* Are we in protected mode? */
250 OldMode = CurrentExecutionContext->Mode;
251 if (OldMode != BlRealMode)
252 {
253 /* FIXME: Not yet implemented */
254 return STATUS_NOT_IMPLEMENTED;
255 }
256
257 /* Use the UEFI version */
258 EfiStatus = EfiBS->CloseProtocol(Handle, Protocol, EfiImageHandle, NULL);
259
260 /* Switch back to protected mode if we came from there */
261 if (OldMode != BlRealMode)
262 {
263 BlpArchSwitchContext(OldMode);
264 }
265
266 /* Normalize not found as success */
267 if (EfiStatus == EFI_NOT_FOUND)
268 {
269 EfiStatus = EFI_SUCCESS;
270 }
271 }
272
273 /* Convert the error to an NTSTATUS */
274 Status = EfiGetNtStatusCode(EfiStatus);
275 }
276
277 /* All done */
278 return Status;
279 }
280
281 NTSTATUS
282 EfiGetVariable (
283 _In_ PWCHAR VariableName,
284 _In_ EFI_GUID* VendorGuid,
285 _Out_opt_ PULONG Attributes,
286 _Inout_ PULONG DataSize,
287 _Out_ PVOID Data
288 )
289 {
290 EFI_STATUS EfiStatus;
291 NTSTATUS Status;
292 BL_ARCH_MODE OldMode;
293 ULONG LocalAttributes;
294
295 /* Are we in protected mode? */
296 OldMode = CurrentExecutionContext->Mode;
297 if (OldMode != BlRealMode)
298 {
299 /* FIXME: Not yet implemented */
300 return STATUS_NOT_IMPLEMENTED;
301 }
302
303 /* Call the runtime API */
304 EfiStatus = EfiRT->GetVariable(VariableName,
305 VendorGuid,
306 (UINT32*)&LocalAttributes,
307 (UINTN*)DataSize,
308 Data);
309
310 /* Switch back to protected mode if we came from there */
311 if (OldMode != BlRealMode)
312 {
313 BlpArchSwitchContext(OldMode);
314 }
315
316 /* Return attributes back to the caller if asked to */
317 if (Attributes)
318 {
319 *Attributes = LocalAttributes;
320 }
321
322 /* Convert the error to an NTSTATUS and return it */
323 Status = EfiGetNtStatusCode(EfiStatus);
324 return Status;
325 }
326
327 NTSTATUS
328 BlpSecureBootEFIIsEnabled (
329 VOID
330 )
331 {
332 NTSTATUS Status;
333 BOOLEAN SetupMode, SecureBoot;
334 ULONG DataSize;
335
336 /* Assume setup mode enabled, and no secure boot */
337 SecureBoot = FALSE;
338 SetupMode = TRUE;
339
340 /* Get the SetupMode variable */
341 DataSize = sizeof(SetupMode);
342 Status = EfiGetVariable(L"SetupMode",
343 &EfiGlobalVariable,
344 NULL,
345 &DataSize,
346 &SetupMode);
347 if (NT_SUCCESS(Status))
348 {
349 /* If it worked, get the SecureBoot variable */
350 DataSize = sizeof(SecureBoot);
351 Status = EfiGetVariable(L"SecureBoot",
352 &EfiGlobalVariable,
353 NULL,
354 &DataSize,
355 &SecureBoot);
356 if (NT_SUCCESS(Status))
357 {
358 /* In setup mode or without secureboot turned on, return failure */
359 if ((SecureBoot != TRUE) || (SetupMode))
360 {
361 Status = STATUS_INVALID_SIGNATURE;
362 }
363
364 // BlpSbdiStateFlags |= 8u;
365 }
366 }
367
368 /* Return secureboot status */
369 return Status;
370 }
371
372 NTSTATUS
373 BlSecureBootIsEnabled (
374 _Out_ PBOOLEAN SecureBootEnabled
375 )
376 {
377 NTSTATUS Status;
378
379 /* Have we checked before ? */
380 if (!BlpFirmwareChecked)
381 {
382 /* First time checking */
383 Status = BlpSecureBootEFIIsEnabled();
384 if NT_SUCCESS(Status)
385 {
386 /* Yep, it's on */
387 BlpFirmwareEnabled = TRUE;
388 }
389
390 /* Don't check again */
391 BlpFirmwareChecked = TRUE;
392 }
393
394 /* Return the firmware result */
395 *SecureBootEnabled = BlpFirmwareEnabled;
396 return STATUS_SUCCESS;
397 }
398
399 NTSTATUS
400 BlSecureBootCheckForFactoryReset (
401 VOID
402 )
403 {
404 BOOLEAN SecureBootEnabled;
405 NTSTATUS Status;
406 ULONG DataSize;
407
408 /* Initialize locals */
409 DataSize = 0;
410 SecureBootEnabled = FALSE;
411
412 /* Check if secureboot is enabled */
413 Status = BlSecureBootIsEnabled(&SecureBootEnabled);
414 if (!(NT_SUCCESS(Status)) || !(SecureBootEnabled))
415 {
416 /* It's not. Check if there's a revocation list */
417 Status = EfiGetVariable(L"RevocationList",
418 &BlpEfiSecureBootPrivateNamespace,
419 NULL,
420 &DataSize,
421 NULL);
422 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
423 {
424 /* We don't support this yet */
425 EfiPrintf(L"Not yet supported\r\n");
426 Status = STATUS_NOT_IMPLEMENTED;
427 }
428 }
429
430 /* Return back to the caller */
431 return Status;
432 }
433
434 NTSTATUS
435 EfiConInReset (
436 VOID
437 )
438 {
439 BL_ARCH_MODE OldMode;
440 EFI_STATUS EfiStatus;
441
442 /* Are we in protected mode? */
443 OldMode = CurrentExecutionContext->Mode;
444 if (OldMode != BlRealMode)
445 {
446 /* FIXME: Not yet implemented */
447 return STATUS_NOT_IMPLEMENTED;
448 }
449
450 /* Make the EFI call */
451 EfiStatus = EfiConIn->Reset(EfiConIn, FALSE);
452
453 /* Switch back to protected mode if we came from there */
454 if (OldMode != BlRealMode)
455 {
456 BlpArchSwitchContext(OldMode);
457 }
458
459 /* Convert the error to an NTSTATUS */
460 return EfiGetNtStatusCode(EfiStatus);
461 }
462
463 NTSTATUS
464 EfiConInExReset (
465 VOID
466 )
467 {
468 BL_ARCH_MODE OldMode;
469 EFI_STATUS EfiStatus;
470
471 /* Are we in protected mode? */
472 OldMode = CurrentExecutionContext->Mode;
473 if (OldMode != BlRealMode)
474 {
475 /* FIXME: Not yet implemented */
476 return STATUS_NOT_IMPLEMENTED;
477 }
478
479 /* Make the EFI call */
480 EfiStatus = EfiConInEx->Reset(EfiConInEx, FALSE);
481
482 /* Switch back to protected mode if we came from there */
483 if (OldMode != BlRealMode)
484 {
485 BlpArchSwitchContext(OldMode);
486 }
487
488 /* Convert the error to an NTSTATUS */
489 return EfiGetNtStatusCode(EfiStatus);
490 }
491
492 NTSTATUS
493 EfiConInExSetState (
494 _In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ConInEx,
495 _In_ EFI_KEY_TOGGLE_STATE* KeyToggleState
496 )
497 {
498 BL_ARCH_MODE OldMode;
499 EFI_STATUS EfiStatus;
500
501 /* Are we in protected mode? */
502 OldMode = CurrentExecutionContext->Mode;
503 if (OldMode != BlRealMode)
504 {
505 /* FIXME: Not yet implemented */
506 return STATUS_NOT_IMPLEMENTED;
507 }
508
509 /* Make the EFI call */
510 EfiStatus = ConInEx->SetState(ConInEx, KeyToggleState);
511
512 /* Switch back to protected mode if we came from there */
513 if (OldMode != BlRealMode)
514 {
515 BlpArchSwitchContext(OldMode);
516 }
517
518 /* Convert the error to an NTSTATUS */
519 return EfiGetNtStatusCode(EfiStatus);
520 }
521
522 NTSTATUS
523 EfiSetWatchdogTimer (
524 VOID
525 )
526 {
527 BL_ARCH_MODE OldMode;
528 EFI_STATUS EfiStatus;
529
530 /* Are we in protected mode? */
531 OldMode = CurrentExecutionContext->Mode;
532 if (OldMode != BlRealMode)
533 {
534 /* FIXME: Not yet implemented */
535 return STATUS_NOT_IMPLEMENTED;
536 }
537
538 /* Make the EFI call */
539 EfiStatus = EfiBS->SetWatchdogTimer(0, 0, 0, NULL);
540
541 /* Switch back to protected mode if we came from there */
542 if (OldMode != BlRealMode)
543 {
544 BlpArchSwitchContext(OldMode);
545 }
546
547 /* Convert the error to an NTSTATUS */
548 return EfiGetNtStatusCode(EfiStatus);
549 }
550
551 NTSTATUS
552 EfiGetMemoryMap (
553 _Out_ UINTN* MemoryMapSize,
554 _Inout_ EFI_MEMORY_DESCRIPTOR *MemoryMap,
555 _Out_ UINTN* MapKey,
556 _Out_ UINTN* DescriptorSize,
557 _Out_ UINTN* DescriptorVersion
558 )
559 {
560 BL_ARCH_MODE OldMode;
561 EFI_STATUS EfiStatus;
562
563 /* Are we in protected mode? */
564 OldMode = CurrentExecutionContext->Mode;
565 if (OldMode != BlRealMode)
566 {
567 /* FIXME: Not yet implemented */
568 return STATUS_NOT_IMPLEMENTED;
569 }
570
571 /* Make the EFI call */
572 EfiStatus = EfiBS->GetMemoryMap(MemoryMapSize,
573 MemoryMap,
574 MapKey,
575 DescriptorSize,
576 DescriptorVersion);
577
578 /* Switch back to protected mode if we came from there */
579 if (OldMode != BlRealMode)
580 {
581 BlpArchSwitchContext(OldMode);
582 }
583
584 /* Convert the error to an NTSTATUS */
585 return EfiGetNtStatusCode(EfiStatus);
586 }
587
588 NTSTATUS
589 EfiFreePages (
590 _In_ ULONG Pages,
591 _In_ EFI_PHYSICAL_ADDRESS PhysicalAddress
592 )
593 {
594 BL_ARCH_MODE OldMode;
595 EFI_STATUS EfiStatus;
596
597 /* Are we in protected mode? */
598 OldMode = CurrentExecutionContext->Mode;
599 if (OldMode != BlRealMode)
600 {
601 /* FIXME: Not yet implemented */
602 return STATUS_NOT_IMPLEMENTED;
603 }
604
605 /* Make the EFI call */
606 EfiStatus = EfiBS->FreePages(PhysicalAddress, Pages);
607
608 /* Switch back to protected mode if we came from there */
609 if (OldMode != BlRealMode)
610 {
611 BlpArchSwitchContext(OldMode);
612 }
613
614 /* Convert the error to an NTSTATUS */
615 return EfiGetNtStatusCode(EfiStatus);
616 }
617
618 NTSTATUS
619 EfiStall (
620 _In_ ULONG StallTime
621 )
622 {
623 BL_ARCH_MODE OldMode;
624 EFI_STATUS EfiStatus;
625
626 /* Are we in protected mode? */
627 OldMode = CurrentExecutionContext->Mode;
628 if (OldMode != BlRealMode)
629 {
630 /* FIXME: Not yet implemented */
631 return STATUS_NOT_IMPLEMENTED;
632 }
633
634 /* Make the EFI call */
635 EfiStatus = EfiBS->Stall(StallTime);
636
637 /* Switch back to protected mode if we came from there */
638 if (OldMode != BlRealMode)
639 {
640 BlpArchSwitchContext(OldMode);
641 }
642
643 /* Convert the error to an NTSTATUS */
644 return EfiGetNtStatusCode(EfiStatus);
645 }
646
647 NTSTATUS
648 EfiConOutQueryMode (
649 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
650 _In_ ULONG Mode,
651 _In_ UINTN* Columns,
652 _In_ UINTN* Rows
653 )
654 {
655 BL_ARCH_MODE OldMode;
656 EFI_STATUS EfiStatus;
657
658 /* Are we in protected mode? */
659 OldMode = CurrentExecutionContext->Mode;
660 if (OldMode != BlRealMode)
661 {
662 /* FIXME: Not yet implemented */
663 return STATUS_NOT_IMPLEMENTED;
664 }
665
666 /* Make the EFI call */
667 EfiStatus = TextInterface->QueryMode(TextInterface, Mode, Columns, Rows);
668
669 /* Switch back to protected mode if we came from there */
670 if (OldMode != BlRealMode)
671 {
672 BlpArchSwitchContext(OldMode);
673 }
674
675 /* Convert the error to an NTSTATUS */
676 return EfiGetNtStatusCode(EfiStatus);
677 }
678
679 NTSTATUS
680 EfiConOutSetMode (
681 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
682 _In_ ULONG Mode
683 )
684 {
685 BL_ARCH_MODE OldMode;
686 EFI_STATUS EfiStatus;
687
688 /* Are we in protected mode? */
689 OldMode = CurrentExecutionContext->Mode;
690 if (OldMode != BlRealMode)
691 {
692 /* FIXME: Not yet implemented */
693 return STATUS_NOT_IMPLEMENTED;
694 }
695
696 /* Make the EFI call */
697 EfiStatus = TextInterface->SetMode(TextInterface, Mode);
698
699 /* Switch back to protected mode if we came from there */
700 if (OldMode != BlRealMode)
701 {
702 BlpArchSwitchContext(OldMode);
703 }
704
705 /* Convert the error to an NTSTATUS */
706 return EfiGetNtStatusCode(EfiStatus);
707 }
708
709 NTSTATUS
710 EfiConOutSetAttribute (
711 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
712 _In_ ULONG Attribute
713 )
714 {
715 BL_ARCH_MODE OldMode;
716 EFI_STATUS EfiStatus;
717
718 /* Are we in protected mode? */
719 OldMode = CurrentExecutionContext->Mode;
720 if (OldMode != BlRealMode)
721 {
722 /* FIXME: Not yet implemented */
723 return STATUS_NOT_IMPLEMENTED;
724 }
725
726 /* Make the EFI call */
727 EfiStatus = TextInterface->SetAttribute(TextInterface, Attribute);
728
729 /* Switch back to protected mode if we came from there */
730 if (OldMode != BlRealMode)
731 {
732 BlpArchSwitchContext(OldMode);
733 }
734
735 /* Convert the error to an NTSTATUS */
736 return EfiGetNtStatusCode(EfiStatus);
737 }
738
739 NTSTATUS
740 EfiConOutSetCursorPosition (
741 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
742 _In_ ULONG Column,
743 _In_ ULONG Row
744 )
745 {
746 BL_ARCH_MODE OldMode;
747 EFI_STATUS EfiStatus;
748
749 /* Are we in protected mode? */
750 OldMode = CurrentExecutionContext->Mode;
751 if (OldMode != BlRealMode)
752 {
753 /* FIXME: Not yet implemented */
754 return STATUS_NOT_IMPLEMENTED;
755 }
756
757 /* Make the EFI call */
758 EfiStatus = TextInterface->SetCursorPosition(TextInterface, Column, Row);
759
760 /* Switch back to protected mode if we came from there */
761 if (OldMode != BlRealMode)
762 {
763 BlpArchSwitchContext(OldMode);
764 }
765
766 /* Convert the error to an NTSTATUS */
767 return EfiGetNtStatusCode(EfiStatus);
768 }
769
770 NTSTATUS
771 EfiConOutEnableCursor (
772 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
773 _In_ BOOLEAN Visible
774 )
775 {
776 BL_ARCH_MODE OldMode;
777 EFI_STATUS EfiStatus;
778
779 /* Are we in protected mode? */
780 OldMode = CurrentExecutionContext->Mode;
781 if (OldMode != BlRealMode)
782 {
783 /* FIXME: Not yet implemented */
784 return STATUS_NOT_IMPLEMENTED;
785 }
786
787 /* Make the EFI call */
788 EfiStatus = TextInterface->EnableCursor(TextInterface, Visible);
789
790 /* Switch back to protected mode if we came from there */
791 if (OldMode != BlRealMode)
792 {
793 BlpArchSwitchContext(OldMode);
794 }
795
796 /* Convert the error to an NTSTATUS */
797 return EfiGetNtStatusCode(EfiStatus);
798 }
799
800 NTSTATUS
801 EfiConOutOutputString (
802 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
803 _In_ PWCHAR String
804 )
805 {
806 BL_ARCH_MODE OldMode;
807 EFI_STATUS EfiStatus;
808
809 /* Are we in protected mode? */
810 OldMode = CurrentExecutionContext->Mode;
811 if (OldMode != BlRealMode)
812 {
813 /* FIXME: Not yet implemented */
814 return STATUS_NOT_IMPLEMENTED;
815 }
816
817 /* Make the EFI call */
818 EfiStatus = TextInterface->OutputString(TextInterface, String);
819
820 /* Switch back to protected mode if we came from there */
821 if (OldMode != BlRealMode)
822 {
823 BlpArchSwitchContext(OldMode);
824 }
825
826 /* Convert the error to an NTSTATUS */
827 return EfiGetNtStatusCode(EfiStatus);
828 }
829
830
831 VOID
832 EfiConOutReadCurrentMode (
833 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
834 _Out_ EFI_SIMPLE_TEXT_OUTPUT_MODE* Mode
835 )
836 {
837 BL_ARCH_MODE OldMode;
838
839 /* Are we in protected mode? */
840 OldMode = CurrentExecutionContext->Mode;
841 if (OldMode != BlRealMode)
842 {
843 /* FIXME: Not yet implemented */
844 return;
845 }
846
847 /* Make the EFI call */
848 RtlCopyMemory(Mode, TextInterface->Mode, sizeof(*Mode));
849
850 /* Switch back to protected mode if we came from there */
851 if (OldMode != BlRealMode)
852 {
853 BlpArchSwitchContext(OldMode);
854 }
855 }
856
857 VOID
858 EfiGopGetFrameBuffer (
859 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
860 _Out_ PHYSICAL_ADDRESS* FrameBuffer,
861 _Out_ UINTN *FrameBufferSize
862 )
863 {
864 BL_ARCH_MODE OldMode;
865
866 /* Are we in protected mode? */
867 OldMode = CurrentExecutionContext->Mode;
868 if (OldMode != BlRealMode)
869 {
870 /* FIXME: Not yet implemented */
871 return;
872 }
873
874 /* Make the EFI call */
875 FrameBuffer->QuadPart = GopInterface->Mode->FrameBufferBase;
876 *FrameBufferSize = GopInterface->Mode->FrameBufferSize;
877
878 /* Switch back to protected mode if we came from there */
879 if (OldMode != BlRealMode)
880 {
881 BlpArchSwitchContext(OldMode);
882 }
883 }
884
885 NTSTATUS
886 EfiGopGetCurrentMode (
887 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
888 _Out_ UINTN* Mode,
889 _Out_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Information
890 )
891 {
892 BL_ARCH_MODE OldMode;
893
894 /* Are we in protected mode? */
895 OldMode = CurrentExecutionContext->Mode;
896 if (OldMode != BlRealMode)
897 {
898 /* FIXME: Not yet implemented */
899 return STATUS_NOT_IMPLEMENTED;
900 }
901
902 /* Make the EFI call */
903 *Mode = GopInterface->Mode->Mode;
904 RtlCopyMemory(Information, GopInterface->Mode->Info, sizeof(*Information));
905
906 /* Switch back to protected mode if we came from there */
907 if (OldMode != BlRealMode)
908 {
909 BlpArchSwitchContext(OldMode);
910 }
911
912 /* Return back */
913 return STATUS_SUCCESS;
914 }
915
916 NTSTATUS
917 EfiGopSetMode (
918 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
919 _In_ ULONG Mode
920 )
921 {
922 BL_ARCH_MODE OldMode;
923 EFI_STATUS EfiStatus;
924 BOOLEAN ModeChanged;
925 NTSTATUS Status;
926
927 /* Are we in protected mode? */
928 OldMode = CurrentExecutionContext->Mode;
929 if (OldMode != BlRealMode)
930 {
931 /* FIXME: Not yet implemented */
932 return STATUS_NOT_IMPLEMENTED;
933 }
934
935 /* Make the EFI call */
936 if (Mode == GopInterface->Mode->Mode)
937 {
938 EfiStatus = EFI_SUCCESS;
939 ModeChanged = FALSE;
940 }
941 {
942 EfiStatus = GopInterface->SetMode(GopInterface, Mode);
943 ModeChanged = TRUE;
944 }
945
946 /* Switch back to protected mode if we came from there */
947 if (OldMode != BlRealMode)
948 {
949 BlpArchSwitchContext(OldMode);
950 }
951
952 /* Print out to the debugger if the mode was changed */
953 Status = EfiGetNtStatusCode(EfiStatus);
954 if ((ModeChanged) && (NT_SUCCESS(Status)))
955 {
956 /* FIXME @TODO: Should be BlStatusPrint */
957 EfiPrintf(L"Console video mode set to 0x%x\r\n", Mode);
958 }
959
960 /* Convert the error to an NTSTATUS */
961 return Status;
962 }
963
964 NTSTATUS
965 EfiLocateHandleBuffer (
966 _In_ EFI_LOCATE_SEARCH_TYPE SearchType,
967 _In_ EFI_GUID *Protocol,
968 _Inout_ PULONG HandleCount,
969 _Inout_ EFI_HANDLE** Buffer
970 )
971 {
972 BL_ARCH_MODE OldMode;
973 EFI_STATUS EfiStatus;
974 UINTN BufferSize;
975
976 /* Bail out if we're missing parameters */
977 if (!(Buffer) || !(HandleCount))
978 {
979 return STATUS_INVALID_PARAMETER;
980 }
981
982 /* Check if a buffer was passed in*/
983 if (*Buffer)
984 {
985 /* Then we should already have a buffer size*/
986 BufferSize = sizeof(EFI_HANDLE) * *HandleCount;
987 }
988 else
989 {
990 /* Then no buffer size exists */
991 BufferSize = 0;
992 }
993
994 /* Are we in protected mode? */
995 OldMode = CurrentExecutionContext->Mode;
996 if (OldMode != BlRealMode)
997 {
998 /* FIXME: Not yet implemented */
999 return STATUS_NOT_IMPLEMENTED;
1000 }
1001
1002 /* Try the first time */
1003 EfiStatus = EfiBS->LocateHandle(SearchType, Protocol, NULL, &BufferSize, *Buffer);
1004 if (EfiStatus == EFI_BUFFER_TOO_SMALL)
1005 {
1006 /* Did we have an existing buffer? */
1007 if (*Buffer)
1008 {
1009 /* Free it */
1010 BlMmFreeHeap(*Buffer);
1011 }
1012
1013 /* Allocate a new one */
1014 *Buffer = BlMmAllocateHeap(BufferSize);
1015 if (!(*Buffer))
1016 {
1017 /* No space, fail */
1018 return STATUS_NO_MEMORY;
1019 }
1020
1021 /* Try again */
1022 EfiStatus = EfiBS->LocateHandle(SearchType, Protocol, NULL, &BufferSize, *Buffer);
1023
1024 /* Switch back to protected mode if we came from there */
1025 if (OldMode != BlRealMode)
1026 {
1027 BlpArchSwitchContext(OldMode);
1028 }
1029 }
1030
1031 /* Return the number of handles */
1032 *HandleCount = BufferSize / sizeof(EFI_HANDLE);
1033
1034 /* Convert the error to an NTSTATUS */
1035 return EfiGetNtStatusCode(EfiStatus);
1036 }
1037
1038 VOID
1039 EfiResetSystem (
1040 _In_ EFI_RESET_TYPE ResetType
1041 )
1042 {
1043 BL_ARCH_MODE OldMode;
1044
1045 /* Are we in protected mode? */
1046 OldMode = CurrentExecutionContext->Mode;
1047 if (OldMode != BlRealMode)
1048 {
1049 /* FIXME: Not yet implemented */
1050 return;
1051 }
1052
1053 /* Call the EFI runtime */
1054 EfiRT->ResetSystem(ResetType, EFI_SUCCESS, 0, NULL);
1055 }
1056
1057 NTSTATUS
1058 EfiConnectController (
1059 _In_ EFI_HANDLE ControllerHandle
1060 )
1061 {
1062 BL_ARCH_MODE OldMode;
1063 EFI_STATUS EfiStatus;
1064
1065 /* Is this EFI 1.02? */
1066 if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
1067 {
1068 /* This function didn't exist back then */
1069 return STATUS_NOT_SUPPORTED;
1070 }
1071
1072 /* Are we in protected mode? */
1073 OldMode = CurrentExecutionContext->Mode;
1074 if (OldMode != BlRealMode)
1075 {
1076 /* FIXME: Not yet implemented */
1077 return STATUS_NOT_IMPLEMENTED;
1078 }
1079
1080 /* Make the EFI call */
1081 EfiStatus = EfiBS->ConnectController(ControllerHandle, NULL, NULL, TRUE);
1082
1083 /* Switch back to protected mode if we came from there */
1084 if (OldMode != BlRealMode)
1085 {
1086 BlpArchSwitchContext(OldMode);
1087 }
1088
1089 /* Convert the error to an NTSTATUS */
1090 return EfiGetNtStatusCode(EfiStatus);
1091 }
1092
1093 NTSTATUS
1094 EfiAllocatePages (
1095 _In_ ULONG Type,
1096 _In_ ULONG Pages,
1097 _Inout_ EFI_PHYSICAL_ADDRESS* Memory
1098 )
1099 {
1100 BL_ARCH_MODE OldMode;
1101 EFI_STATUS EfiStatus;
1102
1103 /* Are we in protected mode? */
1104 OldMode = CurrentExecutionContext->Mode;
1105 if (OldMode != BlRealMode)
1106 {
1107 /* FIXME: Not yet implemented */
1108 return STATUS_NOT_IMPLEMENTED;
1109 }
1110
1111 /* Make the EFI call */
1112 EfiStatus = EfiBS->AllocatePages(Type, EfiLoaderData, Pages, Memory);
1113
1114 /* Switch back to protected mode if we came from there */
1115 if (OldMode != BlRealMode)
1116 {
1117 BlpArchSwitchContext(OldMode);
1118 }
1119
1120 /* Convert the error to an NTSTATUS */
1121 return EfiGetNtStatusCode(EfiStatus);
1122 }
1123
1124 NTSTATUS
1125 EfipGetSystemTable (
1126 _In_ EFI_GUID *TableGuid,
1127 _Out_ PPHYSICAL_ADDRESS TableAddress
1128 )
1129 {
1130 ULONG i;
1131 NTSTATUS Status;
1132
1133 /* Assume failure */
1134 Status = STATUS_NOT_FOUND;
1135
1136 /* Loop through the configuration tables */
1137 for (i = 0; i < EfiST->NumberOfTableEntries; i++)
1138 {
1139 /* Check if this one matches the one we want */
1140 if (RtlEqualMemory(&EfiST->ConfigurationTable[i].VendorGuid,
1141 TableGuid,
1142 sizeof(*TableGuid)))
1143 {
1144 /* Return its address */
1145 TableAddress->QuadPart = (ULONG_PTR)EfiST->ConfigurationTable[i].VendorTable;
1146 Status = STATUS_SUCCESS;
1147 break;
1148 }
1149 }
1150
1151 /* Return the search result */
1152 return Status;
1153 }
1154
1155 NTSTATUS
1156 EfipGetRsdt (
1157 _Out_ PPHYSICAL_ADDRESS FoundRsdt
1158 )
1159 {
1160 NTSTATUS Status;
1161 ULONG Length;
1162 PHYSICAL_ADDRESS RsdpAddress, Rsdt;
1163 PRSDP Rsdp;
1164
1165 /* Assume failure */
1166 Length = 0;
1167 Rsdp = NULL;
1168
1169 /* Check if we already know it */
1170 if (EfiRsdt.QuadPart)
1171 {
1172 /* Return it */
1173 *FoundRsdt = EfiRsdt;
1174 return STATUS_SUCCESS;
1175 }
1176
1177 /* Otherwise, look for the ACPI 2.0 RSDP (XSDT really) */
1178 Status = EfipGetSystemTable(&EfiRootAcpiTableGuid, &RsdpAddress);
1179 if (!NT_SUCCESS(Status))
1180 {
1181 /* Didn't fint it, look for the ACPI 1.0 RSDP (RSDT really) */
1182 Status = EfipGetSystemTable(&EfiRootAcpiTable10Guid, &RsdpAddress);
1183 if (!NT_SUCCESS(Status))
1184 {
1185 return Status;
1186 }
1187 }
1188
1189 /* Map it */
1190 Length = sizeof(*Rsdp);
1191 Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
1192 0,
1193 Length,
1194 RsdpAddress);
1195 if (NT_SUCCESS(Status))
1196 {
1197 /* Check the revision (anything >= 2.0 is XSDT) */
1198 if (Rsdp->Revision)
1199 {
1200 /* Check if the table is bigger than just its header */
1201 if (Rsdp->Length > Length)
1202 {
1203 /* Capture the real length */
1204 Length = Rsdp->Length;
1205
1206 /* Unmap our header mapping */
1207 BlMmUnmapVirtualAddressEx(Rsdp, sizeof(*Rsdp));
1208
1209 /* And map the whole thing now */
1210 Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
1211 0,
1212 Length,
1213 RsdpAddress);
1214 if (!NT_SUCCESS(Status))
1215 {
1216 return Status;
1217 }
1218 }
1219
1220 /* Read the XSDT address from the table*/
1221 Rsdt = Rsdp->XsdtAddress;
1222 }
1223 else
1224 {
1225 /* ACPI 1.0 so just read the RSDT */
1226 Rsdt.QuadPart = Rsdp->RsdtAddress;
1227 }
1228
1229 /* Save it for later */
1230 EfiRsdt = Rsdt;
1231
1232 /* And return it back */
1233 *FoundRsdt = Rsdt;
1234 }
1235
1236 /* Check if we had mapped the RSDP */
1237 if (Rsdp)
1238 {
1239 /* Unmap it */
1240 BlMmUnmapVirtualAddressEx(Rsdp, Length);
1241 }
1242
1243 /* Return search result back to caller */
1244 return Status;
1245 }
1246
1247 BL_MEMORY_ATTR
1248 MmFwpGetOsAttributeType (
1249 _In_ ULONGLONG Attribute
1250 )
1251 {
1252 BL_MEMORY_ATTR OsAttribute = 0;
1253
1254 if (Attribute & EFI_MEMORY_UC)
1255 {
1256 OsAttribute = BlMemoryUncached;
1257 }
1258
1259 if (Attribute & EFI_MEMORY_WC)
1260 {
1261 OsAttribute |= BlMemoryWriteCombined;
1262 }
1263
1264 if (Attribute & EFI_MEMORY_WT)
1265 {
1266 OsAttribute |= BlMemoryWriteThrough;
1267 }
1268
1269 if (Attribute & EFI_MEMORY_WB)
1270 {
1271 OsAttribute |= BlMemoryWriteBack;
1272 }
1273
1274 if (Attribute & EFI_MEMORY_UCE)
1275 {
1276 OsAttribute |= BlMemoryUncachedExported;
1277 }
1278
1279 if (Attribute & EFI_MEMORY_WP)
1280 {
1281 OsAttribute |= BlMemoryWriteProtected;
1282 }
1283
1284 if (Attribute & EFI_MEMORY_RP)
1285 {
1286 OsAttribute |= BlMemoryReadProtected;
1287 }
1288
1289 if (Attribute & EFI_MEMORY_XP)
1290 {
1291 OsAttribute |= BlMemoryExecuteProtected;
1292 }
1293
1294 if (Attribute & EFI_MEMORY_RUNTIME)
1295 {
1296 OsAttribute |= BlMemoryRuntime;
1297 }
1298
1299 return OsAttribute;
1300 }
1301
1302 BL_MEMORY_TYPE
1303 MmFwpGetOsMemoryType (
1304 _In_ EFI_MEMORY_TYPE MemoryType
1305 )
1306 {
1307 BL_MEMORY_TYPE OsType;
1308
1309 switch (MemoryType)
1310 {
1311 case EfiLoaderCode:
1312 case EfiLoaderData:
1313 OsType = BlLoaderMemory;
1314 break;
1315
1316 case EfiBootServicesCode:
1317 case EfiBootServicesData:
1318 OsType = BlEfiBootMemory;
1319 break;
1320
1321 case EfiRuntimeServicesCode:
1322 case EfiRuntimeServicesData:
1323 OsType = BlEfiRuntimeMemory;
1324 break;
1325
1326 case EfiConventionalMemory:
1327 OsType = BlConventionalMemory;
1328 break;
1329
1330 case EfiUnusableMemory:
1331 OsType = BlUnusableMemory;
1332 break;
1333
1334 case EfiACPIReclaimMemory:
1335 OsType = BlAcpiReclaimMemory;
1336 break;
1337
1338 case EfiACPIMemoryNVS:
1339 OsType = BlAcpiNvsMemory;
1340 break;
1341
1342 case EfiMemoryMappedIO:
1343 OsType = BlDeviceIoMemory;
1344 break;
1345
1346 case EfiMemoryMappedIOPortSpace:
1347 OsType = BlDevicePortMemory;
1348 break;
1349
1350 case EfiPalCode:
1351 OsType = BlPalMemory;
1352 break;
1353
1354 default:
1355 OsType = BlReservedMemory;
1356 break;
1357 }
1358
1359 return OsType;
1360 }
1361
1362 NTSTATUS
1363 MmFwGetMemoryMap (
1364 _Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap,
1365 _In_ ULONG Flags
1366 )
1367 {
1368 BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
1369 BOOLEAN UseEfiBuffer, HaveRamDisk;
1370 NTSTATUS Status;
1371 ULONGLONG Pages, StartPage, EndPage;
1372 UINTN EfiMemoryMapSize, MapKey, DescriptorSize, DescriptorVersion;
1373 EFI_PHYSICAL_ADDRESS EfiBuffer = 0;
1374 EFI_MEMORY_DESCRIPTOR* EfiMemoryMap;
1375 EFI_STATUS EfiStatus;
1376 BL_ARCH_MODE OldMode;
1377 EFI_MEMORY_DESCRIPTOR EfiDescriptor;
1378 BL_MEMORY_TYPE MemoryType;
1379 PBL_MEMORY_DESCRIPTOR Descriptor;
1380 BL_MEMORY_ATTR Attribute;
1381
1382 /* Initialize EFI memory map attributes */
1383 EfiMemoryMapSize = MapKey = DescriptorSize = DescriptorVersion = 0;
1384
1385 /* Increment the nesting depth */
1386 MmDescriptorCallTreeCount++;
1387
1388 /* Determine if we should use EFI or our own allocator at this point */
1389 UseEfiBuffer = Flags & BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS;
1390 if (!(LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED))
1391 {
1392 UseEfiBuffer = TRUE;
1393 }
1394
1395 /* Bail out if we don't have a list to use */
1396 if (MemoryMap == NULL)
1397 {
1398 Status = STATUS_INVALID_PARAMETER;
1399 goto Quickie;
1400 }
1401
1402 /* Free the current descriptor list */
1403 MmMdFreeList(MemoryMap);
1404
1405 /* Call into EFI to get the size of the memory map */
1406 Status = EfiGetMemoryMap(&EfiMemoryMapSize,
1407 NULL,
1408 &MapKey,
1409 &DescriptorSize,
1410 &DescriptorVersion);
1411 if (Status != STATUS_BUFFER_TOO_SMALL)
1412 {
1413 /* This should've failed because our buffer was too small, nothing else */
1414 EfiPrintf(L"Got strange EFI status for memory map: %lx\r\n", Status);
1415 if (NT_SUCCESS(Status))
1416 {
1417 Status = STATUS_UNSUCCESSFUL;
1418 }
1419 goto Quickie;
1420 }
1421
1422 /* Add 4 more descriptors just in case things changed */
1423 EfiMemoryMapSize += (4 * DescriptorSize);
1424 Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
1425 EfiPrintf(L"Memory map size: %lx bytes, %d pages\r\n", EfiMemoryMapSize, Pages);
1426
1427 /* Should we use EFI to grab memory? */
1428 if (UseEfiBuffer)
1429 {
1430 /* Yes -- request one more page to align up correctly */
1431 Pages++;
1432
1433 /* Grab the required pages */
1434 Status = EfiAllocatePages(AllocateAnyPages,
1435 Pages,
1436 &EfiBuffer);
1437 if (!NT_SUCCESS(Status))
1438 {
1439 EfiPrintf(L"EFI allocation failed: %lx\r\n", Status);
1440 goto Quickie;
1441 }
1442
1443 /* Free the pages for now */
1444 Status = EfiFreePages(Pages, EfiBuffer);
1445 if (!NT_SUCCESS(Status))
1446 {
1447 EfiBuffer = 0;
1448 goto Quickie;
1449 }
1450
1451 /* Now round to the actual buffer size, removing the extra page */
1452 EfiBuffer = ROUND_TO_PAGES(EfiBuffer);
1453 Pages--;
1454 Status = EfiAllocatePages(AllocateAddress,
1455 Pages,
1456 &EfiBuffer);
1457 if (!NT_SUCCESS(Status))
1458 {
1459 EfiBuffer = 0;
1460 goto Quickie;
1461 }
1462
1463 /* Get the final aligned size and proper buffer */
1464 EfiMemoryMapSize = EFI_PAGES_TO_SIZE(Pages);
1465 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR*)(ULONG_PTR)EfiBuffer;
1466
1467 /* Switch to real mode if not already in it */
1468 OldMode = CurrentExecutionContext->Mode;
1469 if (OldMode != BlRealMode)
1470 {
1471 BlpArchSwitchContext(BlRealMode);
1472 }
1473
1474 /* Call EFI to get the memory map */
1475 EfiStatus = EfiBS->GetMemoryMap(&EfiMemoryMapSize,
1476 EfiMemoryMap,
1477 &MapKey,
1478 &DescriptorSize,
1479 &DescriptorVersion);
1480
1481 /* Switch back into the previous mode */
1482 if (OldMode != BlRealMode)
1483 {
1484 BlpArchSwitchContext(OldMode);
1485 }
1486
1487 /* Convert the result code */
1488 Status = EfiGetNtStatusCode(EfiStatus);
1489 }
1490 else
1491 {
1492 /* We don't support this path yet */
1493 Status = STATUS_NOT_IMPLEMENTED;
1494 }
1495
1496 /* So far so good? */
1497 if (!NT_SUCCESS(Status))
1498 {
1499 EfiPrintf(L"Failed to get EFI memory map: %lx\r\n", Status);
1500 goto Quickie;
1501 }
1502
1503 /* Did we get correct data from firmware? */
1504 if (((EfiMemoryMapSize % DescriptorSize)) ||
1505 (DescriptorSize < sizeof(EFI_MEMORY_DESCRIPTOR)))
1506 {
1507 EfiPrintf(L"Incorrect descriptor size\r\n");
1508 Status = STATUS_UNSUCCESSFUL;
1509 goto Quickie;
1510 }
1511
1512 /* Did we boot from a RAM disk? */
1513 if ((BlpBootDevice->DeviceType == LocalDevice) &&
1514 (BlpBootDevice->Local.Type == RamDiskDevice))
1515 {
1516 /* We don't handle this yet */
1517 EfiPrintf(L"RAM boot not supported\r\n");
1518 Status = STATUS_NOT_IMPLEMENTED;
1519 goto Quickie;
1520 }
1521 else
1522 {
1523 /* We didn't, so there won't be any need to find the memory descriptor */
1524 HaveRamDisk = FALSE;
1525 }
1526
1527 /* Loop the EFI memory map */
1528 #if 0
1529 EfiPrintf(L"UEFI MEMORY MAP\r\n\r\n");
1530 EfiPrintf(L"TYPE START END ATTRIBUTES\r\n");
1531 EfiPrintf(L"===============================================================\r\n");
1532 #endif
1533 while (EfiMemoryMapSize != 0)
1534 {
1535 /* Check if this is an EFI buffer, but we're not in real mode */
1536 if ((UseEfiBuffer) && (OldMode != BlRealMode))
1537 {
1538 BlpArchSwitchContext(BlRealMode);
1539 }
1540
1541 /* Capture it so we can go back to protected mode (if possible) */
1542 EfiDescriptor = *EfiMemoryMap;
1543
1544 /* Go back to protected mode, if we had switched */
1545 if ((UseEfiBuffer) && (OldMode != BlRealMode))
1546 {
1547 BlpArchSwitchContext(OldMode);
1548 }
1549
1550 /* Convert to OS memory type */
1551 MemoryType = MmFwpGetOsMemoryType(EfiDescriptor.Type);
1552
1553 /* Round up or round down depending on where the memory is coming from */
1554 if (MemoryType == BlConventionalMemory)
1555 {
1556 StartPage = BYTES_TO_PAGES(EfiDescriptor.PhysicalStart);
1557 }
1558 else
1559 {
1560 StartPage = EfiDescriptor.PhysicalStart >> PAGE_SHIFT;
1561 }
1562
1563 /* Calculate the ending page */
1564 EndPage = StartPage + EfiDescriptor.NumberOfPages;
1565
1566 /* If after rounding, we ended up with 0 pages, skip this */
1567 if (StartPage == EndPage)
1568 {
1569 goto LoopAgain;
1570 }
1571 #if 0
1572 EfiPrintf(L"%08X 0x%016I64X-0x%016I64X 0x%I64X\r\n",
1573 MemoryType,
1574 StartPage << PAGE_SHIFT,
1575 EndPage << PAGE_SHIFT,
1576 EfiDescriptor.Attribute);
1577 #endif
1578 /* Check for any range of memory below 1MB */
1579 if (StartPage < 0x100)
1580 {
1581 /* Does this range actually contain NULL? */
1582 if (StartPage == 0)
1583 {
1584 /* Manually create a reserved descriptof for this page */
1585 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1586 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1587 BlReservedMemory,
1588 0,
1589 0,
1590 1);
1591 if (!Descriptor)
1592 {
1593 Status = STATUS_INSUFFICIENT_RESOURCES;
1594 break;
1595 }
1596
1597 /* Add this descriptor into the list */
1598 Status = MmMdAddDescriptorToList(MemoryMap,
1599 Descriptor,
1600 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
1601 if (!NT_SUCCESS(Status))
1602 {
1603 EfiPrintf(L"Failed to add zero page descriptor: %lx\r\n", Status);
1604 break;
1605 }
1606
1607 /* Now handle the rest of the range, unless this was it */
1608 StartPage = 1;
1609 if (EndPage == 1)
1610 {
1611 goto LoopAgain;
1612 }
1613 }
1614
1615 /* Does the range go beyond 1MB? */
1616 if (EndPage > 0x100)
1617 {
1618 /* Then create the descriptor for everything up until the megabyte */
1619 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1620 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1621 MemoryType,
1622 StartPage,
1623 0,
1624 0x100 - StartPage);
1625 if (!Descriptor)
1626 {
1627 Status = STATUS_INSUFFICIENT_RESOURCES;
1628 break;
1629 }
1630
1631 /* Check if this region is currently free RAM */
1632 if (Descriptor->Type == BlConventionalMemory)
1633 {
1634 /* Set the reserved flag on the descriptor */
1635 EfiPrintf(L"Adding magic flag\r\n");
1636 Descriptor->Flags |= BlMemoryReserved;
1637 }
1638
1639 /* Add this descriptor into the list */
1640 Status = MmMdAddDescriptorToList(MemoryMap,
1641 Descriptor,
1642 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
1643 if (!NT_SUCCESS(Status))
1644 {
1645 EfiPrintf(L"Failed to add 1MB descriptor: %lx\r\n", Status);
1646 break;
1647 }
1648
1649 /* Now handle the rest of the range above 1MB */
1650 StartPage = 0x100;
1651 }
1652 }
1653
1654 /* Check if we loaded from a RAM disk */
1655 if (HaveRamDisk)
1656 {
1657 /* We don't handle this yet */
1658 EfiPrintf(L"RAM boot not supported\r\n");
1659 Status = STATUS_NOT_IMPLEMENTED;
1660 goto Quickie;
1661 }
1662
1663 /* Create a descriptor for the current range */
1664 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1665 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1666 MemoryType,
1667 StartPage,
1668 0,
1669 EndPage - StartPage);
1670 if (!Descriptor)
1671 {
1672 Status = STATUS_INSUFFICIENT_RESOURCES;
1673 break;
1674 }
1675
1676 /* Check if this region is currently free RAM below 1MB */
1677 if ((Descriptor->Type == BlConventionalMemory) && (EndPage <= 0x100))
1678 {
1679 /* Set the reserved flag on the descriptor */
1680 EfiPrintf(L"Adding magic flag\r\n");
1681 Descriptor->Flags |= BlMemoryReserved;
1682 }
1683
1684 /* Add the descriptor to the list, requesting coalescing as asked */
1685 Status = MmMdAddDescriptorToList(MemoryMap,
1686 Descriptor,
1687 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG |
1688 ((Flags & BL_MM_FLAG_REQUEST_COALESCING) ?
1689 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG : 0));
1690 if (!NT_SUCCESS(Status))
1691 {
1692 EfiPrintf(L"Failed to add full descriptor: %lx\r\n", Status);
1693 break;
1694 }
1695
1696 LoopAgain:
1697 /* Consume this descriptor, and move to the next one */
1698 EfiMemoryMapSize -= DescriptorSize;
1699 EfiMemoryMap = (PVOID)((ULONG_PTR)EfiMemoryMap + DescriptorSize);
1700 }
1701
1702 /* FIXME: @TODO: Mark the EfiBuffer as free, since we're about to free it */
1703 /* For now, just "leak" the 1-2 pages... */
1704
1705 Quickie:
1706 /* Free the EFI buffer, if we had one */
1707 if (EfiBuffer != 0)
1708 {
1709 EfiFreePages(Pages, EfiBuffer);
1710 }
1711
1712 /* On failure, free the memory map if one was passed in */
1713 if (!NT_SUCCESS(Status) && (MemoryMap != NULL))
1714 {
1715 MmMdFreeList(MemoryMap);
1716 }
1717
1718 /* Decrement the nesting depth and return */
1719 MmDescriptorCallTreeCount--;
1720 return Status;
1721 }
1722
1723 NTSTATUS
1724 BlpFwInitialize (
1725 _In_ ULONG Phase,
1726 _In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
1727 )
1728 {
1729 NTSTATUS Status = STATUS_SUCCESS;
1730 EFI_KEY_TOGGLE_STATE KeyToggleState;
1731
1732 /* Check if we have valid firmware data */
1733 if (!(FirmwareData) || !(FirmwareData->Version))
1734 {
1735 return STATUS_INVALID_PARAMETER;
1736 }
1737
1738 /* Check which boot phase we're in */
1739 if (Phase != 0)
1740 {
1741 /* Memory manager is ready, open the extended input protocol */
1742 Status = EfiOpenProtocol(EfiST->ConsoleInHandle,
1743 &EfiSimpleTextInputExProtocol,
1744 (PVOID*)&EfiConInEx);
1745 if (NT_SUCCESS(Status))
1746 {
1747 /* Set the initial key toggle state */
1748 KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
1749 EfiConInExSetState(EfiConInEx, &KeyToggleState);
1750 }
1751
1752 /* Setup the watchdog timer */
1753 EfiSetWatchdogTimer();
1754 }
1755 else
1756 {
1757 /* Make a copy of the parameters */
1758 EfiFirmwareParameters = &EfiFirmwareData;
1759
1760 /* Check which version we received */
1761 if (FirmwareData->Version == 1)
1762 {
1763 /* FIXME: Not supported */
1764 Status = STATUS_NOT_SUPPORTED;
1765 }
1766 else if (FirmwareData->Version >= BL_FIRMWARE_DESCRIPTOR_VERSION)
1767 {
1768 /* Version 2 -- save the data */
1769 EfiFirmwareData = *FirmwareData;
1770 EfiSystemTable = FirmwareData->SystemTable;
1771 EfiImageHandle = FirmwareData->ImageHandle;
1772
1773 /* Set the EDK-II style variables as well */
1774 EfiST = EfiSystemTable;
1775 EfiBS = EfiSystemTable->BootServices;
1776 EfiRT = EfiSystemTable->RuntimeServices;
1777 EfiConOut = EfiSystemTable->ConOut;
1778 EfiConIn = EfiSystemTable->ConIn;
1779 EfiConInEx = NULL;
1780 }
1781 else
1782 {
1783 /* Unknown version */
1784 Status = STATUS_NOT_SUPPORTED;
1785 }
1786 }
1787
1788 /* Return the initialization state */
1789 return Status;
1790 }
1791
1792 NTSTATUS
1793 BlFwGetParameters (
1794 _In_ PBL_FIRMWARE_DESCRIPTOR Parameters
1795 )
1796 {
1797 /* Make sure we got an argument */
1798 if (!Parameters)
1799 {
1800 return STATUS_INVALID_PARAMETER;
1801 }
1802
1803 /* Copy the static data */
1804 *Parameters = *EfiFirmwareParameters;
1805 return STATUS_SUCCESS;
1806 }
1807
1808 NTSTATUS
1809 BlFwEnumerateDevice (
1810 _In_ PBL_DEVICE_DESCRIPTOR Device
1811 )
1812 {
1813 NTSTATUS Status;
1814 ULONG PathProtocols, BlockProtocols;
1815 EFI_HANDLE* PathArray;
1816 EFI_HANDLE* BlockArray;
1817
1818 /* Initialize locals */
1819 BlockArray = NULL;
1820 PathArray = NULL;
1821 PathProtocols = 0;
1822 BlockProtocols = 0;
1823
1824 /* Enumeration only makes sense on disks or partitions */
1825 if ((Device->DeviceType != DiskDevice) &&
1826 (Device->DeviceType != LegacyPartitionDevice) &&
1827 (Device->DeviceType != PartitionDevice))
1828 {
1829 return STATUS_NOT_SUPPORTED;
1830 }
1831
1832 /* Enumerate the list of device paths */
1833 Status = EfiLocateHandleBuffer(ByProtocol,
1834 &EfiDevicePathProtocol,
1835 &PathProtocols,
1836 &PathArray);
1837 if (NT_SUCCESS(Status))
1838 {
1839 /* Loop through each one */
1840 Status = STATUS_NOT_FOUND;
1841 while (PathProtocols)
1842 {
1843 /* Attempt to connect the driver for this device epath */
1844 Status = EfiConnectController(PathArray[--PathProtocols]);
1845 if (NT_SUCCESS(Status))
1846 {
1847 /* Now enumerate any block I/O devices the driver added */
1848 Status = EfiLocateHandleBuffer(ByProtocol,
1849 &EfiBlockIoProtocol,
1850 &BlockProtocols,
1851 &BlockArray);
1852 if (!NT_SUCCESS(Status))
1853 {
1854 break;
1855 }
1856
1857 /* Loop through each one */
1858 while (BlockProtocols)
1859 {
1860 /* Check if one of the new devices is the one we want */
1861 Status = BlockIoEfiCompareDevice(Device,
1862 BlockArray[--BlockProtocols]);
1863 if (NT_SUCCESS(Status))
1864 {
1865 /* Yep, all done */
1866 goto Quickie;
1867 }
1868 }
1869
1870 /* Move on to the next device path */
1871 BlMmFreeHeap(BlockArray);
1872 BlockArray = NULL;
1873 }
1874 }
1875 }
1876
1877 Quickie:
1878 /* We're done -- free the array of device path protocols, if any */
1879 if (PathArray)
1880 {
1881 BlMmFreeHeap(PathArray);
1882 }
1883
1884 /* We're done -- free the array of block I/O protocols, if any */
1885 if (BlockArray)
1886 {
1887 BlMmFreeHeap(BlockArray);
1888 }
1889
1890 /* Return if we found the device or not */
1891 return Status;
1892 }
1893
1894 /*++
1895 * @name EfiGetEfiStatusCode
1896 *
1897 * The EfiGetEfiStatusCode routine converts an NT Status to an EFI status.
1898 *
1899 * @param Status
1900 * NT Status code to be converted.
1901 *
1902 * @remark Only certain, specific NT status codes are converted to EFI codes.
1903 *
1904 * @return The corresponding EFI Status code, EFI_NO_MAPPING otherwise.
1905 *
1906 *--*/
1907 EFI_STATUS
1908 EfiGetEfiStatusCode(
1909 _In_ NTSTATUS Status
1910 )
1911 {
1912 switch (Status)
1913 {
1914 case STATUS_NOT_SUPPORTED:
1915 return EFI_UNSUPPORTED;
1916 case STATUS_DISK_FULL:
1917 return EFI_VOLUME_FULL;
1918 case STATUS_INSUFFICIENT_RESOURCES:
1919 return EFI_OUT_OF_RESOURCES;
1920 case STATUS_MEDIA_WRITE_PROTECTED:
1921 return EFI_WRITE_PROTECTED;
1922 case STATUS_DEVICE_NOT_READY:
1923 return EFI_NOT_STARTED;
1924 case STATUS_DEVICE_ALREADY_ATTACHED:
1925 return EFI_ALREADY_STARTED;
1926 case STATUS_MEDIA_CHANGED:
1927 return EFI_MEDIA_CHANGED;
1928 case STATUS_INVALID_PARAMETER:
1929 return EFI_INVALID_PARAMETER;
1930 case STATUS_ACCESS_DENIED:
1931 return EFI_ACCESS_DENIED;
1932 case STATUS_BUFFER_TOO_SMALL:
1933 return EFI_BUFFER_TOO_SMALL;
1934 case STATUS_DISK_CORRUPT_ERROR:
1935 return EFI_VOLUME_CORRUPTED;
1936 case STATUS_REQUEST_ABORTED:
1937 return EFI_ABORTED;
1938 case STATUS_NO_MEDIA:
1939 return EFI_NO_MEDIA;
1940 case STATUS_IO_DEVICE_ERROR:
1941 return EFI_DEVICE_ERROR;
1942 case STATUS_INVALID_BUFFER_SIZE:
1943 return EFI_BAD_BUFFER_SIZE;
1944 case STATUS_NOT_FOUND:
1945 return EFI_NOT_FOUND;
1946 case STATUS_DRIVER_UNABLE_TO_LOAD:
1947 return EFI_LOAD_ERROR;
1948 case STATUS_NO_MATCH:
1949 return EFI_NO_MAPPING;
1950 case STATUS_SUCCESS:
1951 return EFI_SUCCESS;
1952 case STATUS_TIMEOUT:
1953 return EFI_TIMEOUT;
1954 default:
1955 return EFI_NO_MAPPING;
1956 }
1957 }
1958
1959 /*++
1960 * @name EfiGetNtStatusCode
1961 *
1962 * The EfiGetNtStatusCode routine converts an EFI Status to an NT status.
1963 *
1964 * @param EfiStatus
1965 * EFI Status code to be converted.
1966 *
1967 * @remark Only certain, specific EFI status codes are converted to NT codes.
1968 *
1969 * @return The corresponding NT Status code, STATUS_UNSUCCESSFUL otherwise.
1970 *
1971 *--*/
1972 NTSTATUS
1973 EfiGetNtStatusCode (
1974 _In_ EFI_STATUS EfiStatus
1975 )
1976 {
1977 switch (EfiStatus)
1978 {
1979 case EFI_NOT_READY:
1980 case EFI_NOT_FOUND:
1981 return STATUS_NOT_FOUND;
1982 case EFI_NO_MEDIA:
1983 return STATUS_NO_MEDIA;
1984 case EFI_MEDIA_CHANGED:
1985 return STATUS_MEDIA_CHANGED;
1986 case EFI_ACCESS_DENIED:
1987 case EFI_SECURITY_VIOLATION:
1988 return STATUS_ACCESS_DENIED;
1989 case EFI_TIMEOUT:
1990 case EFI_NO_RESPONSE:
1991 return STATUS_TIMEOUT;
1992 case EFI_NO_MAPPING:
1993 return STATUS_NO_MATCH;
1994 case EFI_NOT_STARTED:
1995 return STATUS_DEVICE_NOT_READY;
1996 case EFI_ALREADY_STARTED:
1997 return STATUS_DEVICE_ALREADY_ATTACHED;
1998 case EFI_ABORTED:
1999 return STATUS_REQUEST_ABORTED;
2000 case EFI_VOLUME_FULL:
2001 return STATUS_DISK_FULL;
2002 case EFI_DEVICE_ERROR:
2003 return STATUS_IO_DEVICE_ERROR;
2004 case EFI_WRITE_PROTECTED:
2005 return STATUS_MEDIA_WRITE_PROTECTED;
2006 /* @FIXME: ReactOS Headers don't yet have this */
2007 //case EFI_OUT_OF_RESOURCES:
2008 //return STATUS_INSUFFICIENT_NVRAM_RESOURCES;
2009 case EFI_VOLUME_CORRUPTED:
2010 return STATUS_DISK_CORRUPT_ERROR;
2011 case EFI_BUFFER_TOO_SMALL:
2012 return STATUS_BUFFER_TOO_SMALL;
2013 case EFI_SUCCESS:
2014 return STATUS_SUCCESS;
2015 case EFI_LOAD_ERROR:
2016 return STATUS_DRIVER_UNABLE_TO_LOAD;
2017 case EFI_INVALID_PARAMETER:
2018 return STATUS_INVALID_PARAMETER;
2019 case EFI_UNSUPPORTED:
2020 return STATUS_NOT_SUPPORTED;
2021 case EFI_BAD_BUFFER_SIZE:
2022 return STATUS_INVALID_BUFFER_SIZE;
2023 default:
2024 return STATUS_UNSUCCESSFUL;
2025 }
2026 }