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