[BOOTMGFW]
[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
27 EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
28 EFI_GUID EfiUgaDrawProtocol = EFI_UGA_DRAW_PROTOCOL_GUID;
29 EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
30 EFI_GUID EfiDevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID;
31 EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
32
33 WCHAR BlScratchBuffer[8192];
34
35 /* FUNCTIONS *****************************************************************/
36
37 VOID
38 EfiPrintf (
39 _In_ PWCHAR Format,
40 ...
41 )
42 {
43 va_list args;
44 va_start(args, Format);
45
46 /* Capture the buffer in our scratch pad, and NULL-terminate */
47 vsnwprintf(BlScratchBuffer, RTL_NUMBER_OF(BlScratchBuffer) - 1, Format, args);
48 BlScratchBuffer[RTL_NUMBER_OF(BlScratchBuffer) - 1] = UNICODE_NULL;
49
50 /* Check which mode we're in */
51 if (CurrentExecutionContext->Mode == BlRealMode)
52 {
53 /* Call EFI directly */
54 EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
55 }
56 else
57 {
58 /* FIXME: @TODO: Not yet supported */
59 }
60
61 /* All done */
62 va_end(args);
63 }
64
65 NTSTATUS
66 EfiOpenProtocol (
67 _In_ EFI_HANDLE Handle,
68 _In_ EFI_GUID *Protocol,
69 _Out_ PVOID* Interface
70 )
71 {
72 EFI_STATUS EfiStatus;
73 NTSTATUS Status;
74 BL_ARCH_MODE OldMode;
75
76 /* Are we using virtual memory/ */
77 if (MmTranslationType != BlNone)
78 {
79 /* We need complex tracking to make this work */
80 //Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
81 Status = STATUS_NOT_SUPPORTED;
82 }
83 else
84 {
85 /* Are we in protected mode? */
86 OldMode = CurrentExecutionContext->Mode;
87 if (OldMode != BlRealMode)
88 {
89 /* FIXME: Not yet implemented */
90 return STATUS_NOT_IMPLEMENTED;
91 }
92
93 /* Are we on legacy 1.02? */
94 if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
95 {
96 /* Make the legacy call */
97 EfiStatus = EfiBS->HandleProtocol(Handle, Protocol, Interface);
98 }
99 else
100 {
101 /* Use the UEFI version */
102 EfiStatus = EfiBS->OpenProtocol(Handle,
103 Protocol,
104 Interface,
105 EfiImageHandle,
106 NULL,
107 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
108
109 /* Switch back to protected mode if we came from there */
110 if (OldMode != BlRealMode)
111 {
112 BlpArchSwitchContext(OldMode);
113 }
114 }
115
116 /* Convert the error to an NTSTATUS */
117 Status = EfiGetNtStatusCode(EfiStatus);
118 }
119
120 /* Clear the interface on failure, and return the status */
121 if (!NT_SUCCESS(Status))
122 {
123 *Interface = NULL;
124 }
125
126 return Status;
127 }
128
129 NTSTATUS
130 EfiCloseProtocol (
131 _In_ EFI_HANDLE Handle,
132 _In_ EFI_GUID *Protocol
133 )
134 {
135 EFI_STATUS EfiStatus;
136 NTSTATUS Status;
137 BL_ARCH_MODE OldMode;
138
139 /* Are we using virtual memory/ */
140 if (MmTranslationType != BlNone)
141 {
142 /* We need complex tracking to make this work */
143 //Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
144 Status = STATUS_NOT_SUPPORTED;
145 }
146 else
147 {
148 /* Are we on legacy 1.02? */
149 if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
150 {
151 /* Nothing to close */
152 EfiStatus = STATUS_SUCCESS;
153 }
154 else
155 {
156 /* Are we in protected mode? */
157 OldMode = CurrentExecutionContext->Mode;
158 if (OldMode != BlRealMode)
159 {
160 /* FIXME: Not yet implemented */
161 return STATUS_NOT_IMPLEMENTED;
162 }
163
164 /* Use the UEFI version */
165 EfiStatus = EfiBS->CloseProtocol(Handle, Protocol, EfiImageHandle, NULL);
166
167 /* Switch back to protected mode if we came from there */
168 if (OldMode != BlRealMode)
169 {
170 BlpArchSwitchContext(OldMode);
171 }
172
173 /* Normalize not found as success */
174 if (EfiStatus == EFI_NOT_FOUND)
175 {
176 EfiStatus = EFI_SUCCESS;
177 }
178 }
179
180 /* Convert the error to an NTSTATUS */
181 Status = EfiGetNtStatusCode(EfiStatus);
182 }
183
184 /* All done */
185 return Status;
186 }
187
188 NTSTATUS
189 EfiConInExSetState (
190 _In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ConInEx,
191 _In_ EFI_KEY_TOGGLE_STATE* KeyToggleState
192 )
193 {
194 BL_ARCH_MODE OldMode;
195 EFI_STATUS EfiStatus;
196
197 /* Are we in protected mode? */
198 OldMode = CurrentExecutionContext->Mode;
199 if (OldMode != BlRealMode)
200 {
201 /* FIXME: Not yet implemented */
202 return STATUS_NOT_IMPLEMENTED;
203 }
204
205 /* Make the EFI call */
206 EfiStatus = ConInEx->SetState(ConInEx, KeyToggleState);
207
208 /* Switch back to protected mode if we came from there */
209 if (OldMode != BlRealMode)
210 {
211 BlpArchSwitchContext(OldMode);
212 }
213
214 /* Convert the error to an NTSTATUS */
215 return EfiGetNtStatusCode(EfiStatus);
216 }
217
218 NTSTATUS
219 EfiSetWatchdogTimer (
220 VOID
221 )
222 {
223 BL_ARCH_MODE OldMode;
224 EFI_STATUS EfiStatus;
225
226 /* Are we in protected mode? */
227 OldMode = CurrentExecutionContext->Mode;
228 if (OldMode != BlRealMode)
229 {
230 /* FIXME: Not yet implemented */
231 return STATUS_NOT_IMPLEMENTED;
232 }
233
234 /* Make the EFI call */
235 EfiStatus = EfiBS->SetWatchdogTimer(0, 0, 0, NULL);
236
237 /* Switch back to protected mode if we came from there */
238 if (OldMode != BlRealMode)
239 {
240 BlpArchSwitchContext(OldMode);
241 }
242
243 /* Convert the error to an NTSTATUS */
244 return EfiGetNtStatusCode(EfiStatus);
245 }
246
247 NTSTATUS
248 EfiGetMemoryMap (
249 _Out_ UINTN* MemoryMapSize,
250 _Inout_ EFI_MEMORY_DESCRIPTOR *MemoryMap,
251 _Out_ UINTN* MapKey,
252 _Out_ UINTN* DescriptorSize,
253 _Out_ UINTN* DescriptorVersion
254 )
255 {
256 BL_ARCH_MODE OldMode;
257 EFI_STATUS EfiStatus;
258
259 /* Are we in protected mode? */
260 OldMode = CurrentExecutionContext->Mode;
261 if (OldMode != BlRealMode)
262 {
263 /* FIXME: Not yet implemented */
264 return STATUS_NOT_IMPLEMENTED;
265 }
266
267 /* Make the EFI call */
268 EfiStatus = EfiBS->GetMemoryMap(MemoryMapSize,
269 MemoryMap,
270 MapKey,
271 DescriptorSize,
272 DescriptorVersion);
273
274 /* Switch back to protected mode if we came from there */
275 if (OldMode != BlRealMode)
276 {
277 BlpArchSwitchContext(OldMode);
278 }
279
280 /* Convert the error to an NTSTATUS */
281 return EfiGetNtStatusCode(EfiStatus);
282 }
283
284 NTSTATUS
285 EfiFreePages (
286 _In_ ULONG Pages,
287 _In_ EFI_PHYSICAL_ADDRESS PhysicalAddress
288 )
289 {
290 BL_ARCH_MODE OldMode;
291 EFI_STATUS EfiStatus;
292
293 /* Are we in protected mode? */
294 OldMode = CurrentExecutionContext->Mode;
295 if (OldMode != BlRealMode)
296 {
297 /* FIXME: Not yet implemented */
298 return STATUS_NOT_IMPLEMENTED;
299 }
300
301 /* Make the EFI call */
302 EfiStatus = EfiBS->FreePages(PhysicalAddress, Pages);
303
304 /* Switch back to protected mode if we came from there */
305 if (OldMode != BlRealMode)
306 {
307 BlpArchSwitchContext(OldMode);
308 }
309
310 /* Convert the error to an NTSTATUS */
311 return EfiGetNtStatusCode(EfiStatus);
312 }
313
314 NTSTATUS
315 EfiStall (
316 _In_ ULONG StallTime
317 )
318 {
319 BL_ARCH_MODE OldMode;
320 EFI_STATUS EfiStatus;
321
322 /* Are we in protected mode? */
323 OldMode = CurrentExecutionContext->Mode;
324 if (OldMode != BlRealMode)
325 {
326 /* FIXME: Not yet implemented */
327 return STATUS_NOT_IMPLEMENTED;
328 }
329
330 /* Make the EFI call */
331 EfiStatus = EfiBS->Stall(StallTime);
332
333 /* Switch back to protected mode if we came from there */
334 if (OldMode != BlRealMode)
335 {
336 BlpArchSwitchContext(OldMode);
337 }
338
339 /* Convert the error to an NTSTATUS */
340 return EfiGetNtStatusCode(EfiStatus);
341 }
342
343 NTSTATUS
344 EfiConOutQueryMode (
345 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
346 _In_ ULONG Mode,
347 _In_ UINTN* Columns,
348 _In_ UINTN* Rows
349 )
350 {
351 BL_ARCH_MODE OldMode;
352 EFI_STATUS EfiStatus;
353
354 /* Are we in protected mode? */
355 OldMode = CurrentExecutionContext->Mode;
356 if (OldMode != BlRealMode)
357 {
358 /* FIXME: Not yet implemented */
359 return STATUS_NOT_IMPLEMENTED;
360 }
361
362 /* Make the EFI call */
363 EfiStatus = TextInterface->QueryMode(TextInterface, Mode, Columns, Rows);
364
365 /* Switch back to protected mode if we came from there */
366 if (OldMode != BlRealMode)
367 {
368 BlpArchSwitchContext(OldMode);
369 }
370
371 /* Convert the error to an NTSTATUS */
372 return EfiGetNtStatusCode(EfiStatus);
373 }
374
375 NTSTATUS
376 EfiConOutSetMode (
377 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
378 _In_ ULONG Mode
379 )
380 {
381 BL_ARCH_MODE OldMode;
382 EFI_STATUS EfiStatus;
383
384 /* Are we in protected mode? */
385 OldMode = CurrentExecutionContext->Mode;
386 if (OldMode != BlRealMode)
387 {
388 /* FIXME: Not yet implemented */
389 return STATUS_NOT_IMPLEMENTED;
390 }
391
392 /* Make the EFI call */
393 EfiStatus = TextInterface->SetMode(TextInterface, Mode);
394
395 /* Switch back to protected mode if we came from there */
396 if (OldMode != BlRealMode)
397 {
398 BlpArchSwitchContext(OldMode);
399 }
400
401 /* Convert the error to an NTSTATUS */
402 return EfiGetNtStatusCode(EfiStatus);
403 }
404
405 NTSTATUS
406 EfiConOutSetAttribute (
407 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
408 _In_ ULONG Attribute
409 )
410 {
411 BL_ARCH_MODE OldMode;
412 EFI_STATUS EfiStatus;
413
414 /* Are we in protected mode? */
415 OldMode = CurrentExecutionContext->Mode;
416 if (OldMode != BlRealMode)
417 {
418 /* FIXME: Not yet implemented */
419 return STATUS_NOT_IMPLEMENTED;
420 }
421
422 /* Make the EFI call */
423 EfiStatus = TextInterface->SetAttribute(TextInterface, Attribute);
424
425 /* Switch back to protected mode if we came from there */
426 if (OldMode != BlRealMode)
427 {
428 BlpArchSwitchContext(OldMode);
429 }
430
431 /* Convert the error to an NTSTATUS */
432 return EfiGetNtStatusCode(EfiStatus);
433 }
434
435 NTSTATUS
436 EfiConOutSetCursorPosition (
437 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
438 _In_ ULONG Column,
439 _In_ ULONG Row
440 )
441 {
442 BL_ARCH_MODE OldMode;
443 EFI_STATUS EfiStatus;
444
445 /* Are we in protected mode? */
446 OldMode = CurrentExecutionContext->Mode;
447 if (OldMode != BlRealMode)
448 {
449 /* FIXME: Not yet implemented */
450 return STATUS_NOT_IMPLEMENTED;
451 }
452
453 /* Make the EFI call */
454 EfiStatus = TextInterface->SetCursorPosition(TextInterface, Column, Row);
455
456 /* Switch back to protected mode if we came from there */
457 if (OldMode != BlRealMode)
458 {
459 BlpArchSwitchContext(OldMode);
460 }
461
462 /* Convert the error to an NTSTATUS */
463 return EfiGetNtStatusCode(EfiStatus);
464 }
465
466 NTSTATUS
467 EfiConOutEnableCursor (
468 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
469 _In_ BOOLEAN Visible
470 )
471 {
472 BL_ARCH_MODE OldMode;
473 EFI_STATUS EfiStatus;
474
475 /* Are we in protected mode? */
476 OldMode = CurrentExecutionContext->Mode;
477 if (OldMode != BlRealMode)
478 {
479 /* FIXME: Not yet implemented */
480 return STATUS_NOT_IMPLEMENTED;
481 }
482
483 /* Make the EFI call */
484 EfiStatus = TextInterface->EnableCursor(TextInterface, Visible);
485
486 /* Switch back to protected mode if we came from there */
487 if (OldMode != BlRealMode)
488 {
489 BlpArchSwitchContext(OldMode);
490 }
491
492 /* Convert the error to an NTSTATUS */
493 return EfiGetNtStatusCode(EfiStatus);
494 }
495
496 VOID
497 EfiConOutReadCurrentMode (
498 _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
499 _Out_ EFI_SIMPLE_TEXT_OUTPUT_MODE* Mode
500 )
501 {
502 BL_ARCH_MODE OldMode;
503
504 /* Are we in protected mode? */
505 OldMode = CurrentExecutionContext->Mode;
506 if (OldMode != BlRealMode)
507 {
508 /* FIXME: Not yet implemented */
509 return;
510 }
511
512 /* Make the EFI call */
513 RtlCopyMemory(Mode, TextInterface->Mode, sizeof(*Mode));
514
515 /* Switch back to protected mode if we came from there */
516 if (OldMode != BlRealMode)
517 {
518 BlpArchSwitchContext(OldMode);
519 }
520 }
521
522 VOID
523 EfiGopGetFrameBuffer (
524 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
525 _Out_ PHYSICAL_ADDRESS* FrameBuffer,
526 _Out_ UINTN *FrameBufferSize
527 )
528 {
529 BL_ARCH_MODE OldMode;
530
531 /* Are we in protected mode? */
532 OldMode = CurrentExecutionContext->Mode;
533 if (OldMode != BlRealMode)
534 {
535 /* FIXME: Not yet implemented */
536 return;
537 }
538
539 /* Make the EFI call */
540 FrameBuffer->QuadPart = GopInterface->Mode->FrameBufferBase;
541 *FrameBufferSize = GopInterface->Mode->FrameBufferSize;
542
543 /* Switch back to protected mode if we came from there */
544 if (OldMode != BlRealMode)
545 {
546 BlpArchSwitchContext(OldMode);
547 }
548 }
549
550 NTSTATUS
551 EfiGopGetCurrentMode (
552 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
553 _Out_ UINTN* Mode,
554 _Out_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Information
555 )
556 {
557 BL_ARCH_MODE OldMode;
558
559 /* Are we in protected mode? */
560 OldMode = CurrentExecutionContext->Mode;
561 if (OldMode != BlRealMode)
562 {
563 /* FIXME: Not yet implemented */
564 return STATUS_NOT_IMPLEMENTED;
565 }
566
567 /* Make the EFI call */
568 *Mode = GopInterface->Mode->Mode;
569 RtlCopyMemory(Information, GopInterface->Mode->Info, sizeof(*Information));
570
571 /* Switch back to protected mode if we came from there */
572 if (OldMode != BlRealMode)
573 {
574 BlpArchSwitchContext(OldMode);
575 }
576
577 /* Return back */
578 return STATUS_SUCCESS;
579 }
580
581 NTSTATUS
582 EfiGopSetMode (
583 _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
584 _In_ ULONG Mode
585 )
586 {
587 BL_ARCH_MODE OldMode;
588 EFI_STATUS EfiStatus;
589 BOOLEAN ModeChanged;
590 NTSTATUS Status;
591
592 /* Are we in protected mode? */
593 OldMode = CurrentExecutionContext->Mode;
594 if (OldMode != BlRealMode)
595 {
596 /* FIXME: Not yet implemented */
597 return STATUS_NOT_IMPLEMENTED;
598 }
599
600 /* Make the EFI call */
601 if (Mode == GopInterface->Mode->Mode)
602 {
603 EfiStatus = EFI_SUCCESS;
604 ModeChanged = FALSE;
605 }
606 {
607 EfiStatus = GopInterface->SetMode(GopInterface, Mode);
608 ModeChanged = TRUE;
609 }
610
611 /* Switch back to protected mode if we came from there */
612 if (OldMode != BlRealMode)
613 {
614 BlpArchSwitchContext(OldMode);
615 }
616
617 /* Print out to the debugger if the mode was changed */
618 Status = EfiGetNtStatusCode(EfiStatus);
619 if ((ModeChanged) && (NT_SUCCESS(Status)))
620 {
621 /* FIXME @TODO: Should be BlStatusPrint */
622 EfiPrintf(L"Console video mode set to 0x%x\r\r\n", Mode);
623 }
624
625 /* Convert the error to an NTSTATUS */
626 return Status;
627 }
628
629 NTSTATUS
630 EfiLocateHandleBuffer (
631 _In_ EFI_LOCATE_SEARCH_TYPE SearchType,
632 _In_ EFI_GUID *Protocol,
633 _Inout_ PULONG HandleCount,
634 _Inout_ EFI_HANDLE** Buffer
635 )
636 {
637 BL_ARCH_MODE OldMode;
638 EFI_STATUS EfiStatus;
639 UINTN BufferSize;
640
641 /* Bail out if we're missing parameters */
642 if (!(Buffer) || !(HandleCount))
643 {
644 return STATUS_INVALID_PARAMETER;
645 }
646
647 /* Check if a buffer was passed in*/
648 if (*Buffer)
649 {
650 /* Then we should already have a buffer size*/
651 BufferSize = sizeof(EFI_HANDLE) * *HandleCount;
652 }
653 else
654 {
655 /* Then no buffer size exists */
656 BufferSize = 0;
657 }
658
659 /* Are we in protected mode? */
660 OldMode = CurrentExecutionContext->Mode;
661 if (OldMode != BlRealMode)
662 {
663 /* FIXME: Not yet implemented */
664 return STATUS_NOT_IMPLEMENTED;
665 }
666
667 /* Try the first time */
668 EfiStatus = EfiBS->LocateHandle(SearchType, Protocol, NULL, &BufferSize, *Buffer);
669 if (EfiStatus == EFI_BUFFER_TOO_SMALL)
670 {
671 /* Did we have an existing buffer? */
672 if (*Buffer)
673 {
674 /* Free it */
675 BlMmFreeHeap(*Buffer);
676 }
677
678 /* Allocate a new one */
679 *Buffer = BlMmAllocateHeap(BufferSize);
680 if (!(*Buffer))
681 {
682 /* No space, fail */
683 return STATUS_NO_MEMORY;
684 }
685
686 /* Try again */
687 EfiStatus = EfiBS->LocateHandle(SearchType, Protocol, NULL, &BufferSize, *Buffer);
688
689 /* Switch back to protected mode if we came from there */
690 if (OldMode != BlRealMode)
691 {
692 BlpArchSwitchContext(OldMode);
693 }
694 }
695
696 /* Return the number of handles */
697 *HandleCount = BufferSize / sizeof(EFI_HANDLE);
698
699 /* Convert the error to an NTSTATUS */
700 return EfiGetNtStatusCode(EfiStatus);
701 }
702
703 VOID
704 EfiResetSystem (
705 _In_ EFI_RESET_TYPE ResetType
706 )
707 {
708 BL_ARCH_MODE OldMode;
709
710 /* Are we in protected mode? */
711 OldMode = CurrentExecutionContext->Mode;
712 if (OldMode != BlRealMode)
713 {
714 /* FIXME: Not yet implemented */
715 return;
716 }
717
718 /* Call the EFI runtime */
719 EfiRT->ResetSystem(ResetType, EFI_SUCCESS, 0, NULL);
720 }
721
722 NTSTATUS
723 EfiAllocatePages (
724 _In_ ULONG Type,
725 _In_ ULONG Pages,
726 _Inout_ EFI_PHYSICAL_ADDRESS* Memory
727 )
728 {
729 BL_ARCH_MODE OldMode;
730 EFI_STATUS EfiStatus;
731
732 /* Are we in protected mode? */
733 OldMode = CurrentExecutionContext->Mode;
734 if (OldMode != BlRealMode)
735 {
736 /* FIXME: Not yet implemented */
737 return STATUS_NOT_IMPLEMENTED;
738 }
739
740 /* Make the EFI call */
741 EfiStatus = EfiBS->AllocatePages(Type, EfiLoaderData, Pages, Memory);
742
743 /* Switch back to protected mode if we came from there */
744 if (OldMode != BlRealMode)
745 {
746 BlpArchSwitchContext(OldMode);
747 }
748
749 /* Convert the error to an NTSTATUS */
750 return EfiGetNtStatusCode(EfiStatus);
751 }
752
753 BL_MEMORY_ATTR
754 MmFwpGetOsAttributeType (
755 _In_ ULONGLONG Attribute
756 )
757 {
758 BL_MEMORY_ATTR OsAttribute = 0;
759
760 if (Attribute & EFI_MEMORY_UC)
761 {
762 OsAttribute = BlMemoryUncached;
763 }
764
765 if (Attribute & EFI_MEMORY_WC)
766 {
767 OsAttribute |= BlMemoryWriteCombined;
768 }
769
770 if (Attribute & EFI_MEMORY_WT)
771 {
772 OsAttribute |= BlMemoryWriteThrough;
773 }
774
775 if (Attribute & EFI_MEMORY_WB)
776 {
777 OsAttribute |= BlMemoryWriteBack;
778 }
779
780 if (Attribute & EFI_MEMORY_UCE)
781 {
782 OsAttribute |= BlMemoryUncachedExported;
783 }
784
785 if (Attribute & EFI_MEMORY_WP)
786 {
787 OsAttribute |= BlMemoryWriteProtected;
788 }
789
790 if (Attribute & EFI_MEMORY_RP)
791 {
792 OsAttribute |= BlMemoryReadProtected;
793 }
794
795 if (Attribute & EFI_MEMORY_XP)
796 {
797 OsAttribute |= BlMemoryExecuteProtected;
798 }
799
800 if (Attribute & EFI_MEMORY_RUNTIME)
801 {
802 OsAttribute |= BlMemoryRuntime;
803 }
804
805 return OsAttribute;
806 }
807
808 BL_MEMORY_TYPE
809 MmFwpGetOsMemoryType (
810 _In_ EFI_MEMORY_TYPE MemoryType
811 )
812 {
813 BL_MEMORY_TYPE OsType;
814
815 switch (MemoryType)
816 {
817 case EfiLoaderCode:
818 case EfiLoaderData:
819 OsType = BlLoaderMemory;
820 break;
821
822 case EfiBootServicesCode:
823 case EfiBootServicesData:
824 OsType = BlEfiBootMemory;
825 break;
826
827 case EfiRuntimeServicesCode:
828 case EfiRuntimeServicesData:
829 OsType = BlEfiRuntimeMemory;
830 break;
831
832 case EfiConventionalMemory:
833 OsType = BlConventionalMemory;
834 break;
835
836 case EfiUnusableMemory:
837 OsType = BlUnusableMemory;
838 break;
839
840 case EfiACPIReclaimMemory:
841 OsType = BlAcpiReclaimMemory;
842 break;
843
844 case EfiACPIMemoryNVS:
845 OsType = BlAcpiNvsMemory;
846 break;
847
848 case EfiMemoryMappedIO:
849 OsType = BlDeviceIoMemory;
850 break;
851
852 case EfiMemoryMappedIOPortSpace:
853 OsType = BlDevicePortMemory;
854 break;
855
856 case EfiPalCode:
857 OsType = BlPalMemory;
858 break;
859
860 default:
861 OsType = BlReservedMemory;
862 break;
863 }
864
865 return OsType;
866 }
867
868 NTSTATUS
869 MmFwGetMemoryMap (
870 _Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap,
871 _In_ ULONG Flags
872 )
873 {
874 BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
875 BOOLEAN UseEfiBuffer, HaveRamDisk;
876 NTSTATUS Status;
877 ULONGLONG Pages, StartPage, EndPage;
878 UINTN EfiMemoryMapSize, MapKey, DescriptorSize, DescriptorVersion;
879 EFI_PHYSICAL_ADDRESS EfiBuffer;
880 EFI_MEMORY_DESCRIPTOR* EfiMemoryMap;
881 EFI_STATUS EfiStatus;
882 BL_ARCH_MODE OldMode;
883 EFI_MEMORY_DESCRIPTOR EfiDescriptor;
884 BL_MEMORY_TYPE MemoryType;
885 PBL_MEMORY_DESCRIPTOR Descriptor;
886 BL_MEMORY_ATTR Attribute;
887
888 /* Initialize EFI memory map attributes */
889 EfiMemoryMapSize = MapKey = DescriptorSize = DescriptorVersion = 0;
890
891 /* Increment the nesting depth */
892 MmDescriptorCallTreeCount++;
893
894 /* Determine if we should use EFI or our own allocator at this point */
895 UseEfiBuffer = Flags & BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS;
896 if (!(LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED))
897 {
898 UseEfiBuffer = TRUE;
899 }
900
901 /* Bail out if we don't have a list to use */
902 if (MemoryMap == NULL)
903 {
904 Status = STATUS_INVALID_PARAMETER;
905 goto Quickie;
906 }
907
908 /* Free the current descriptor list */
909 MmMdFreeList(MemoryMap);
910
911 /* Call into EFI to get the size of the memory map */
912 Status = EfiGetMemoryMap(&EfiMemoryMapSize,
913 NULL,
914 &MapKey,
915 &DescriptorSize,
916 &DescriptorVersion);
917 if (Status != STATUS_BUFFER_TOO_SMALL)
918 {
919 /* This should've failed because our buffer was too small, nothing else */
920 EfiPrintf(L"Got strange EFI status for memory map: %lx\r\n", Status);
921 if (NT_SUCCESS(Status))
922 {
923 Status = STATUS_UNSUCCESSFUL;
924 }
925 goto Quickie;
926 }
927
928 /* Add 4 more descriptors just in case things changed */
929 EfiMemoryMapSize += (4 * DescriptorSize);
930 Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
931 EfiPrintf(L"Memory map size: %lx bytes, %d pages\r\n", EfiMemoryMapSize, Pages);
932
933 /* Should we use EFI to grab memory? */
934 if (UseEfiBuffer)
935 {
936 /* Yes -- request one more page to align up correctly */
937 Pages++;
938
939 /* Grab the required pages */
940 Status = EfiAllocatePages(AllocateAnyPages,
941 Pages,
942 &EfiBuffer);
943 if (!NT_SUCCESS(Status))
944 {
945 EfiPrintf(L"EFI allocation failed: %lx\r\n", Status);
946 goto Quickie;
947 }
948
949 /* Free the pages for now */
950 Status = EfiFreePages(Pages, EfiBuffer);
951 if (!NT_SUCCESS(Status))
952 {
953 EfiBuffer = 0;
954 goto Quickie;
955 }
956
957 /* Now round to the actual buffer size, removing the extra page */
958 EfiBuffer = ROUND_TO_PAGES(EfiBuffer);
959 Pages--;
960 Status = EfiAllocatePages(AllocateAddress,
961 Pages,
962 &EfiBuffer);
963 if (!NT_SUCCESS(Status))
964 {
965 EfiBuffer = 0;
966 goto Quickie;
967 }
968
969 /* Get the final aligned size and proper buffer */
970 EfiMemoryMapSize = EFI_PAGES_TO_SIZE(Pages);
971 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR*)(ULONG_PTR)EfiBuffer;
972
973 /* Switch to real mode if not already in it */
974 OldMode = CurrentExecutionContext->Mode;
975 if (OldMode != BlRealMode)
976 {
977 BlpArchSwitchContext(BlRealMode);
978 }
979
980 /* Call EFI to get the memory map */
981 EfiStatus = EfiBS->GetMemoryMap(&EfiMemoryMapSize,
982 EfiMemoryMap,
983 &MapKey,
984 &DescriptorSize,
985 &DescriptorVersion);
986
987 /* Switch back into the previous mode */
988 if (OldMode != BlRealMode)
989 {
990 BlpArchSwitchContext(OldMode);
991 }
992
993 /* Convert the result code */
994 Status = EfiGetNtStatusCode(EfiStatus);
995 }
996 else
997 {
998 /* We don't support this path yet */
999 Status = STATUS_NOT_IMPLEMENTED;
1000 }
1001
1002 /* So far so good? */
1003 if (!NT_SUCCESS(Status))
1004 {
1005 EfiPrintf(L"Failed to get EFI memory map: %lx\r\n", Status);
1006 goto Quickie;
1007 }
1008
1009 /* Did we get correct data from firmware? */
1010 if (((EfiMemoryMapSize % DescriptorSize)) ||
1011 (DescriptorSize < sizeof(EFI_MEMORY_DESCRIPTOR)))
1012 {
1013 EfiPrintf(L"Incorrect descriptor size\r\n");
1014 Status = STATUS_UNSUCCESSFUL;
1015 goto Quickie;
1016 }
1017
1018 /* Did we boot from a RAM disk? */
1019 if ((BlpBootDevice->DeviceType == LocalDevice) &&
1020 (BlpBootDevice->Local.Type == RamDiskDevice))
1021 {
1022 /* We don't handle this yet */
1023 EfiPrintf(L"RAM boot not supported\r\n");
1024 Status = STATUS_NOT_IMPLEMENTED;
1025 goto Quickie;
1026 }
1027 else
1028 {
1029 /* We didn't, so there won't be any need to find the memory descriptor */
1030 HaveRamDisk = FALSE;
1031 }
1032
1033 /* Loop the EFI memory map */
1034 #if 0
1035 EfiPrintf(L"UEFI MEMORY MAP\n\r\n");
1036 EfiPrintf(L"TYPE START END ATTRIBUTES\r\n");
1037 EfiPrintf(L"===============================================================\r\n");
1038 #endif
1039 while (EfiMemoryMapSize != 0)
1040 {
1041 /* Check if this is an EFI buffer, but we're not in real mode */
1042 if ((UseEfiBuffer) && (OldMode != BlRealMode))
1043 {
1044 BlpArchSwitchContext(BlRealMode);
1045 }
1046
1047 /* Capture it so we can go back to protected mode (if possible) */
1048 EfiDescriptor = *EfiMemoryMap;
1049
1050 /* Go back to protected mode, if we had switched */
1051 if ((UseEfiBuffer) && (OldMode != BlRealMode))
1052 {
1053 BlpArchSwitchContext(OldMode);
1054 }
1055
1056 /* Convert to OS memory type */
1057 MemoryType = MmFwpGetOsMemoryType(EfiDescriptor.Type);
1058
1059 /* Round up or round down depending on where the memory is coming from */
1060 if (MemoryType == BlConventionalMemory)
1061 {
1062 StartPage = BYTES_TO_PAGES(EfiDescriptor.PhysicalStart);
1063 }
1064 else
1065 {
1066 StartPage = EfiDescriptor.PhysicalStart >> PAGE_SHIFT;
1067 }
1068
1069 /* Calculate the ending page */
1070 EndPage = StartPage + EfiDescriptor.NumberOfPages;
1071
1072 /* If after rounding, we ended up with 0 pages, skip this */
1073 if (StartPage == EndPage)
1074 {
1075 goto LoopAgain;
1076 }
1077 #if 0
1078 EfiPrintf(L"%08X 0x%016I64X-0x%016I64X 0x%I64X\r\n",
1079 MemoryType,
1080 StartPage << PAGE_SHIFT,
1081 EndPage << PAGE_SHIFT,
1082 EfiDescriptor.Attribute);
1083 #endif
1084 /* Check for any range of memory below 1MB */
1085 if (StartPage < 0x100)
1086 {
1087 /* Does this range actually contain NULL? */
1088 if (StartPage == 0)
1089 {
1090 /* Manually create a reserved descriptof for this page */
1091 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1092 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1093 BlReservedMemory,
1094 0,
1095 0,
1096 1);
1097 if (!Descriptor)
1098 {
1099 Status = STATUS_INSUFFICIENT_RESOURCES;
1100 break;
1101 }
1102
1103 /* Add this descriptor into the list */
1104 Status = MmMdAddDescriptorToList(MemoryMap,
1105 Descriptor,
1106 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
1107 if (!NT_SUCCESS(Status))
1108 {
1109 EfiPrintf(L"Failed to add zero page descriptor: %lx\r\n", Status);
1110 break;
1111 }
1112
1113 /* Now handle the rest of the range, unless this was it */
1114 StartPage = 1;
1115 if (EndPage == 1)
1116 {
1117 goto LoopAgain;
1118 }
1119 }
1120
1121 /* Does the range go beyond 1MB? */
1122 if (EndPage > 0x100)
1123 {
1124 /* Then create the descriptor for everything up until the megabyte */
1125 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1126 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1127 MemoryType,
1128 StartPage,
1129 0,
1130 0x100 - StartPage);
1131 if (!Descriptor)
1132 {
1133 Status = STATUS_INSUFFICIENT_RESOURCES;
1134 break;
1135 }
1136
1137 /* Check if this region is currently free RAM */
1138 if (Descriptor->Type == BlConventionalMemory)
1139 {
1140 /* Set an unknown flag on the descriptor */
1141 Descriptor->Flags |= 0x80000;
1142 }
1143
1144 /* Add this descriptor into the list */
1145 Status = MmMdAddDescriptorToList(MemoryMap,
1146 Descriptor,
1147 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
1148 if (!NT_SUCCESS(Status))
1149 {
1150 EfiPrintf(L"Failed to add 1MB descriptor: %lx\r\n", Status);
1151 break;
1152 }
1153
1154 /* Now handle the rest of the range above 1MB */
1155 StartPage = 0x100;
1156 }
1157 }
1158
1159 /* Check if we loaded from a RAM disk */
1160 if (HaveRamDisk)
1161 {
1162 /* We don't handle this yet */
1163 EfiPrintf(L"RAM boot not supported\r\n");
1164 Status = STATUS_NOT_IMPLEMENTED;
1165 goto Quickie;
1166 }
1167
1168 /* Create a descriptor for the current range */
1169 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
1170 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
1171 MemoryType,
1172 StartPage,
1173 0,
1174 EndPage - StartPage);
1175 if (!Descriptor)
1176 {
1177 Status = STATUS_INSUFFICIENT_RESOURCES;
1178 break;
1179 }
1180
1181 /* Check if this region is currently free RAM below 1MB */
1182 if ((Descriptor->Type == BlConventionalMemory) && (EndPage <= 0x100))
1183 {
1184 /* Set an unknown flag on the descriptor */
1185 Descriptor->Flags |= 0x80000;
1186 }
1187
1188 /* Add the descriptor to the list, requesting coalescing as asked */
1189 Status = MmMdAddDescriptorToList(MemoryMap,
1190 Descriptor,
1191 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG |
1192 (Flags & BL_MM_FLAG_REQUEST_COALESCING) ?
1193 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG : 0);
1194 if (!NT_SUCCESS(Status))
1195 {
1196 EfiPrintf(L"Failed to add full descriptor: %lx\r\n", Status);
1197 break;
1198 }
1199
1200 LoopAgain:
1201 /* Consume this descriptor, and move to the next one */
1202 EfiMemoryMapSize -= DescriptorSize;
1203 EfiMemoryMap = (PVOID)((ULONG_PTR)EfiMemoryMap + DescriptorSize);
1204 }
1205
1206 /* FIXME: @TODO: Mark the EfiBuffer as free, since we're about to free it */
1207 /* For now, just "leak" the 1-2 pages... */
1208
1209 Quickie:
1210 /* Free the EFI buffer, if we had one */
1211 if (EfiBuffer != 0)
1212 {
1213 EfiFreePages(Pages, EfiBuffer);
1214 }
1215
1216 /* On failure, free the memory map if one was passed in */
1217 if (!NT_SUCCESS(Status) && (MemoryMap != NULL))
1218 {
1219 MmMdFreeList(MemoryMap);
1220 }
1221
1222 /* Decrement the nesting depth and return */
1223 MmDescriptorCallTreeCount--;
1224 return Status;
1225 }
1226
1227 NTSTATUS
1228 BlpFwInitialize (
1229 _In_ ULONG Phase,
1230 _In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
1231 )
1232 {
1233 NTSTATUS Status = STATUS_SUCCESS;
1234 EFI_KEY_TOGGLE_STATE KeyToggleState;
1235
1236 /* Check if we have vaild firmware data */
1237 if (!(FirmwareData) || !(FirmwareData->Version))
1238 {
1239 return STATUS_INVALID_PARAMETER;
1240 }
1241
1242 /* Check which boot phase we're in */
1243 if (Phase != 0)
1244 {
1245 /* Memory manager is ready, open the extended input protocol */
1246 Status = EfiOpenProtocol(EfiST->ConsoleInHandle,
1247 &EfiSimpleTextInputExProtocol,
1248 (PVOID*)&EfiConInEx);
1249 if (NT_SUCCESS(Status))
1250 {
1251 /* Set the initial key toggle state */
1252 KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
1253 EfiConInExSetState(EfiConInEx, &KeyToggleState);
1254 }
1255
1256 /* Setup the watchdog timer */
1257 EfiSetWatchdogTimer();
1258 }
1259 else
1260 {
1261 /* Make a copy of the parameters */
1262 EfiFirmwareParameters = &EfiFirmwareData;
1263
1264 /* Check which version we received */
1265 if (FirmwareData->Version == 1)
1266 {
1267 /* FIXME: Not supported */
1268 Status = STATUS_NOT_SUPPORTED;
1269 }
1270 else if (FirmwareData->Version >= 2)
1271 {
1272 /* Version 2 -- save the data */
1273 EfiFirmwareData = *FirmwareData;
1274 EfiSystemTable = FirmwareData->SystemTable;
1275 EfiImageHandle = FirmwareData->ImageHandle;
1276
1277 /* Set the EDK-II style variables as well */
1278 EfiST = EfiSystemTable;
1279 EfiBS = EfiSystemTable->BootServices;
1280 EfiRT = EfiSystemTable->RuntimeServices;
1281 EfiConOut = EfiSystemTable->ConOut;
1282 EfiConIn = EfiSystemTable->ConIn;
1283 EfiConInEx = NULL;
1284 }
1285 else
1286 {
1287 /* Unknown version */
1288 Status = STATUS_NOT_SUPPORTED;
1289 }
1290 }
1291
1292 /* Return the initialization state */
1293 return Status;
1294 }
1295