]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/BiosVideoThunkDxe/BiosVideo.c
c8b090cadd9d2ea0be32290067a480098f603c95
[mirror_edk2.git] / DuetPkg / BiosVideoThunkDxe / BiosVideo.c
1 /*++
2
3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 BiosVideo.c
15
16 Abstract:
17
18 ConsoleOut Routines that speak VGA.
19
20 Revision History
21
22 --*/
23
24 #include "BiosVideo.h"
25
26
27 //
28 // EFI Driver Binding Protocol Instance
29 //
30 EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
31 BiosVideoDriverBindingSupported,
32 BiosVideoDriverBindingStart,
33 BiosVideoDriverBindingStop,
34 0x3,
35 NULL,
36 NULL
37 };
38
39 //
40 // Global lookup tables for VGA graphics modes
41 //
42 UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
43
44 UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
45
46 UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
47
48 THUNK_CONTEXT mThunkContext;
49
50 EFI_LEGACY_8259_PROTOCOL *mLegacy8259 = NULL;
51
52 #define EFI_CPU_EFLAGS_IF 0x200
53
54 EFI_UGA_PIXEL mVgaColorToUgaColor[] = {
55 {
56 0x00,
57 0x00,
58 0x00,
59 0x00
60 },
61 {
62 0x98,
63 0x00,
64 0x00,
65 0x00
66 },
67 {
68 0x00,
69 0x98,
70 0x00,
71 0x00
72 },
73 {
74 0x98,
75 0x98,
76 0x00,
77 0x00
78 },
79 {
80 0x00,
81 0x00,
82 0x98,
83 0x00
84 },
85 {
86 0x98,
87 0x00,
88 0x98,
89 0x00
90 },
91 {
92 0x00,
93 0x98,
94 0x98,
95 0x00
96 },
97 {
98 0x98,
99 0x98,
100 0x98,
101 0x00
102 },
103 {
104 0x10,
105 0x10,
106 0x10,
107 0x00
108 },
109 {
110 0xff,
111 0x10,
112 0x10,
113 0x00
114 },
115 {
116 0x10,
117 0xff,
118 0x10,
119 0x00
120 },
121 {
122 0xff,
123 0xff,
124 0x10,
125 0x00
126 },
127 {
128 0x10,
129 0x10,
130 0xff,
131 0x00
132 },
133 {
134 0xf0,
135 0x10,
136 0xff,
137 0x00
138 },
139 {
140 0x10,
141 0xff,
142 0xff,
143 0x00
144 },
145 {
146 0xff,
147 0xff,
148 0xff,
149 0x00
150 }
151 };
152
153 VOID
154 InitializeBiosIntCaller (
155 VOID
156 );
157
158 VOID
159 InitializeInterruptRedirection (
160 VOID
161 );
162
163 BOOLEAN
164 EFIAPI
165 LegacyBiosInt86 (
166 IN UINT8 BiosInt,
167 IN EFI_IA32_REGISTER_SET *Regs
168 );
169
170 EFI_STATUS
171 EFIAPI
172 BiosVideoDriverEntryPoint (
173 IN EFI_HANDLE ImageHandle,
174 IN EFI_SYSTEM_TABLE *SystemTable
175 )
176 /*++
177
178 Routine Description:
179
180 Driver Entry Point.
181
182 Arguments:
183
184 ImageHandle - Handle of driver image.
185 SystemTable - Pointer to system table.
186
187 Returns:
188
189 EFI_STATUS
190
191 --*/
192 {
193 EFI_STATUS Status;
194
195 Status = EfiLibInstallDriverBindingComponentName2 (
196 ImageHandle,
197 SystemTable,
198 &gBiosVideoDriverBinding,
199 ImageHandle,
200 &gBiosVideoComponentName,
201 &gBiosVideoComponentName2
202 );
203
204 return Status;
205 }
206
207 VOID
208 EFIAPI
209 BiosVideoExitBootServices (
210 EFI_EVENT Event,
211 VOID *Context
212 )
213 /*++
214
215 Routine Description:
216
217 Callback function for exit boot service event
218
219 Arguments:
220
221 Event - EFI_EVENT structure
222 Context - Event context
223
224 Returns:
225
226 None
227
228 --*/
229 {
230 /*
231 BIOS_VIDEO_DEV *BiosVideoPrivate;
232 EFI_IA32_REGISTER_SET Regs;
233
234 //
235 // Get our context
236 //
237 BiosVideoPrivate = (BIOS_VIDEO_DEV *) Context;
238
239 //
240 // Set the 80x25 Text VGA Mode
241 //
242 Regs.H.AH = 0x00;
243 Regs.H.AL = 0x83;
244 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
245
246 Regs.H.AH = 0x11;
247 Regs.H.AL = 0x14;
248 Regs.H.BL = 0;
249 BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
250 */
251 }
252
253 EFI_STATUS
254 EFIAPI
255 BiosVideoDriverBindingSupported (
256 IN EFI_DRIVER_BINDING_PROTOCOL *This,
257 IN EFI_HANDLE Controller,
258 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
259 )
260 /*++
261
262 Routine Description:
263
264 Supported.
265
266 Arguments:
267
268 This - Pointer to driver binding protocol
269 Controller - Controller handle to connect
270 RemainingDevicePath - A pointer to the remaining portion of a device path
271
272
273 Returns:
274
275 EFI_STATUS - EFI_SUCCESS:This controller can be managed by this driver,
276 Otherwise, this controller cannot be managed by this driver
277
278 --*/
279 {
280 EFI_STATUS Status;
281 EFI_LEGACY_8259_PROTOCOL *Legacy8259;
282 EFI_PCI_IO_PROTOCOL *PciIo;
283
284 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported\n"));
285
286 //
287 // See if the Legacy BIOS Protocol is available
288 //
289 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Legacy8259);
290 if (EFI_ERROR (Status)) {
291 return Status;
292 }
293 //
294 // Open the IO Abstraction(s) needed to perform the supported test
295 //
296 Status = gBS->OpenProtocol (
297 Controller,
298 &gEfiPciIoProtocolGuid,
299 (VOID **) &PciIo,
300 This->DriverBindingHandle,
301 Controller,
302 EFI_OPEN_PROTOCOL_BY_DRIVER
303 );
304 if (EFI_ERROR (Status)) {
305 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported: Fail to open PciIo protocol!\n"));
306 return Status;
307 }
308
309 if (!BiosVideoIsVga (PciIo)) {
310 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported: Is not VGA!\n"));
311 Status = EFI_UNSUPPORTED;
312 }
313
314 gBS->CloseProtocol (
315 Controller,
316 &gEfiPciIoProtocolGuid,
317 This->DriverBindingHandle,
318 Controller
319 );
320
321 return Status;
322 }
323
324 EFI_STATUS
325 EFIAPI
326 BiosVideoDriverBindingStart (
327 IN EFI_DRIVER_BINDING_PROTOCOL *This,
328 IN EFI_HANDLE Controller,
329 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
330 )
331 /*++
332
333 Routine Description:
334
335 Install UGA Draw Protocol onto VGA device handles
336
337 Arguments:
338
339 This - Pointer to driver binding protocol
340 Controller - Controller handle to connect
341 RemainingDevicePath - A pointer to the remaining portion of a device path
342
343 Returns:
344
345 EFI_STATUS
346
347 --*/
348 {
349 EFI_STATUS Status;
350 BIOS_VIDEO_DEV *BiosVideoPrivate;
351
352 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart\n"));
353 //
354 // Initialize local variables
355 //
356 BiosVideoPrivate = NULL;
357
358 //
359 // Allocate the private device structure
360 //
361 Status = gBS->AllocatePool (
362 EfiBootServicesData,
363 sizeof (BIOS_VIDEO_DEV),
364 &BiosVideoPrivate
365 );
366 if (EFI_ERROR (Status)) {
367 goto Done;
368 }
369
370 ZeroMem (BiosVideoPrivate, sizeof (BIOS_VIDEO_DEV));
371
372 //
373 // See if the Legacy BIOS Protocol is available
374 //
375 Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
376 if (EFI_ERROR (Status)) {
377 goto Done;
378 }
379
380 //
381 // Prepare for status code
382 //
383 Status = gBS->HandleProtocol (
384 Controller,
385 &gEfiDevicePathProtocolGuid,
386 &BiosVideoPrivate->DevicePath
387 );
388 if (EFI_ERROR (Status)) {
389 goto Done;
390 }
391 //
392 // Open the IO Abstraction(s) needed
393 //
394 Status = gBS->OpenProtocol (
395 Controller,
396 &gEfiPciIoProtocolGuid,
397 (VOID **) &(BiosVideoPrivate->PciIo),
398 This->DriverBindingHandle,
399 Controller,
400 EFI_OPEN_PROTOCOL_BY_DRIVER
401 );
402 if (EFI_ERROR (Status)) {
403 goto Done;
404 }
405
406 DEBUG ((EFI_D_INFO, "InitializeBiosIntCaller\n"));
407 InitializeBiosIntCaller();
408 InitializeInterruptRedirection();
409 DEBUG ((EFI_D_INFO, "InitializeBiosIntCaller Finished!\n"));
410
411 if (!BiosVideoIsVga (BiosVideoPrivate->PciIo)) {
412 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: not VGA\n"));
413 Status = EFI_UNSUPPORTED;
414 goto Done;
415 }
416
417 BiosVideoPrivate->VgaCompatible = TRUE;
418 //
419 // Initialize the private device structure
420 //
421 BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
422 BiosVideoPrivate->Handle = Controller;
423
424 /**
425 Status = gBS->CreateEvent (
426 EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
427 EFI_TPL_NOTIFY,
428 BiosVideoExitBootServices,
429 BiosVideoPrivate,
430 &BiosVideoPrivate->ExitBootServicesEvent
431 );
432 if (EFI_ERROR (Status)) {
433 goto Done;
434 }
435 **/
436
437 //
438 // Fill in UGA Draw specific mode structures
439 //
440 BiosVideoPrivate->HardwareNeedsStarting = TRUE;
441 BiosVideoPrivate->CurrentMode = 0;
442 BiosVideoPrivate->MaxMode = 0;
443 BiosVideoPrivate->ModeData = NULL;
444 BiosVideoPrivate->LineBuffer = NULL;
445 BiosVideoPrivate->VgaFrameBuffer = NULL;
446 BiosVideoPrivate->VbeFrameBuffer = NULL;
447
448 //
449 // Fill in the VGA Mini Port Protocol fields
450 //
451 BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode;
452 BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
453 BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
454 BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
455 BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
456 BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
457 BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
458
459 //
460 // Assume that UGA Draw will be produced until proven otherwise
461 //
462 BiosVideoPrivate->ProduceUgaDraw = TRUE;
463
464 //
465 // Check for VESA BIOS Extensions for modes that are compatible with UGA Draw
466 //
467 //CpuDeadLoop();
468 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Before check VBE!\n"));
469 Status = BiosVideoCheckForVbe (BiosVideoPrivate);
470 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: check VBE status=%r!\n", Status));
471
472 if (EFI_ERROR (Status)) {
473 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Fail to check VBE!\n"));
474 //
475 // The VESA BIOS Extensions are not compatible with UGA Draw, so check for support
476 // for the standard 640x480 16 color VGA mode
477 //
478 if (BiosVideoPrivate->VgaCompatible) {
479 Status = BiosVideoCheckForVga (BiosVideoPrivate);
480 }
481
482 if (EFI_ERROR (Status)) {
483 //
484 // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
485 // not produce the UGA Draw protocol. Instead, produce the VGA MiniPort Protocol.
486 //
487 BiosVideoPrivate->ProduceUgaDraw = FALSE;
488
489 //
490 // INT services are available, so on the 80x25 and 80x50 text mode are supported
491 //
492 BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
493 }
494 }
495
496 if (BiosVideoPrivate->ProduceUgaDraw) {
497 DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Produce Uga Draw!\n"));
498 //
499 // Install UGA Draw Protocol
500 //
501 Status = gBS->InstallMultipleProtocolInterfaces (
502 &Controller,
503 &gEfiUgaDrawProtocolGuid,
504 &BiosVideoPrivate->UgaDraw,
505 NULL
506 );
507 } else {
508 //
509 // Install VGA Mini Port Protocol
510 //
511 Status = gBS->InstallMultipleProtocolInterfaces (
512 &Controller,
513 &gEfiVgaMiniPortProtocolGuid,
514 &BiosVideoPrivate->VgaMiniPort,
515 NULL
516 );
517 }
518
519 Done:
520 if (EFI_ERROR (Status)) {
521 if (BiosVideoPrivate != NULL) {
522 //
523 // Free mode data
524 //
525 if (BiosVideoPrivate->ModeData != NULL) {
526 gBS->FreePool (BiosVideoPrivate->ModeData);
527 }
528 //
529 // Free memory allocated below 1MB
530 //
531 if (BiosVideoPrivate->PagesBelow1MB != 0) {
532 gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
533 }
534
535 if (BiosVideoPrivate->PciIo != NULL) {
536 //
537 // Release PCI I/O and UGA Draw Protocols on the controller handle.
538 //
539 gBS->CloseProtocol (
540 Controller,
541 &gEfiPciIoProtocolGuid,
542 This->DriverBindingHandle,
543 Controller
544 );
545 }
546 //
547 // Close the ExitBootServices event
548 //
549 if (BiosVideoPrivate->ExitBootServicesEvent != NULL) {
550 gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
551 }
552 //
553 // Free private data structure
554 //
555 gBS->FreePool (BiosVideoPrivate);
556 }
557 }
558
559 return Status;
560 }
561
562 EFI_STATUS
563 EFIAPI
564 BiosVideoDriverBindingStop (
565 IN EFI_DRIVER_BINDING_PROTOCOL *This,
566 IN EFI_HANDLE Controller,
567 IN UINTN NumberOfChildren,
568 IN EFI_HANDLE *ChildHandleBuffer
569 )
570 /*++
571
572 Routine Description:
573
574 Stop.
575
576 Arguments:
577
578 This - Pointer to driver binding protocol
579 Controller - Controller handle to connect
580 NumberOfChilren - Number of children handle created by this driver
581 ChildHandleBuffer - Buffer containing child handle created
582
583 Returns:
584
585 EFI_SUCCESS - Driver disconnected successfully from controller
586 EFI_UNSUPPORTED - Cannot find BIOS_VIDEO_DEV structure
587
588 --*/
589 {
590 EFI_STATUS Status;
591 EFI_UGA_DRAW_PROTOCOL *Uga;
592 EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
593 BIOS_VIDEO_DEV *BiosVideoPrivate;
594 EFI_IA32_REGISTER_SET Regs;
595
596 BiosVideoPrivate = NULL;
597
598 Status = gBS->OpenProtocol (
599 Controller,
600 &gEfiUgaDrawProtocolGuid,
601 (VOID **) &Uga,
602 This->DriverBindingHandle,
603 Controller,
604 EFI_OPEN_PROTOCOL_GET_PROTOCOL
605 );
606 if (!EFI_ERROR (Status)) {
607 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (Uga);
608 }
609
610 Status = gBS->OpenProtocol (
611 Controller,
612 &gEfiVgaMiniPortProtocolGuid,
613 (VOID **) &VgaMiniPort,
614 This->DriverBindingHandle,
615 Controller,
616 EFI_OPEN_PROTOCOL_GET_PROTOCOL
617 );
618 if (!EFI_ERROR (Status)) {
619 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
620 }
621
622 if (BiosVideoPrivate == NULL) {
623 return EFI_UNSUPPORTED;
624 }
625
626 if (BiosVideoPrivate->ProduceUgaDraw) {
627 Status = gBS->UninstallMultipleProtocolInterfaces (
628 Controller,
629 &gEfiUgaDrawProtocolGuid,
630 &BiosVideoPrivate->UgaDraw,
631 NULL
632 );
633 } else {
634 Status = gBS->UninstallMultipleProtocolInterfaces (
635 Controller,
636 &gEfiVgaMiniPortProtocolGuid,
637 &BiosVideoPrivate->VgaMiniPort,
638 NULL
639 );
640 }
641
642 if (EFI_ERROR (Status)) {
643 return Status;
644 }
645
646 gBS->SetMem (&Regs, sizeof (Regs), 0);
647
648 //
649 // Set the 80x25 Text VGA Mode
650 //
651 Regs.H.AH = 0x00;
652 Regs.H.AL = 0x03;
653 LegacyBiosInt86 (0x10, &Regs);
654
655 Regs.H.AH = 0x11;
656 Regs.H.AL = 0x14;
657 Regs.H.BL = 0;
658 LegacyBiosInt86 (0x10, &Regs);
659
660 //
661 // Do not disable IO/memory decode since that would prevent legacy ROM from working
662 //
663 //
664 // Free VGA Frame Buffer
665 //
666 if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
667 gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer);
668 }
669 //
670 // Free VBE Frame Buffer
671 //
672 if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
673 gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer);
674 }
675 //
676 // Free line buffer
677 //
678 if (BiosVideoPrivate->LineBuffer != NULL) {
679 gBS->FreePool (BiosVideoPrivate->LineBuffer);
680 }
681 //
682 // Free mode data
683 //
684 if (BiosVideoPrivate->ModeData != NULL) {
685 gBS->FreePool (BiosVideoPrivate->ModeData);
686 }
687 //
688 // Free memory allocated below 1MB
689 //
690 if (BiosVideoPrivate->PagesBelow1MB != 0) {
691 gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
692 }
693
694 if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
695 gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
696 }
697 //
698 // Release PCI I/O and UGA Draw Protocols on the controller handle.
699 //
700 gBS->CloseProtocol (
701 Controller,
702 &gEfiPciIoProtocolGuid,
703 This->DriverBindingHandle,
704 Controller
705 );
706
707 //
708 // Close the ExitBootServices event
709 //
710 gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
711
712 //
713 // Free private data structure
714 //
715 gBS->FreePool (BiosVideoPrivate);
716
717 return EFI_SUCCESS;
718 }
719
720 #define PCI_DEVICE_ENABLED (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE)
721
722
723 BOOLEAN
724 BiosVideoIsVga (
725 IN EFI_PCI_IO_PROTOCOL *PciIo
726 )
727 {
728 EFI_STATUS Status;
729 BOOLEAN VgaCompatible;
730 PCI_TYPE00 Pci;
731
732 VgaCompatible = FALSE;
733
734 //
735 // Read the PCI Configuration Header
736 //
737 Status = PciIo->Pci.Read (
738 PciIo,
739 EfiPciIoWidthUint32,
740 0,
741 sizeof (Pci) / sizeof (UINT32),
742 &Pci
743 );
744 if (EFI_ERROR (Status)) {
745 return VgaCompatible;
746 }
747
748 //
749 // See if this is a VGA compatible controller or not
750 //
751 if ((Pci.Hdr.Command & PCI_DEVICE_ENABLED) == PCI_DEVICE_ENABLED) {
752 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_OLD && Pci.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA) {
753 //
754 // Base Class 0x00 Sub-Class 0x01 - Backward compatible VGA device
755 //
756 VgaCompatible = TRUE;
757 }
758
759 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY && Pci.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA && Pci.Hdr.ClassCode[0] == 0x00) {
760 //
761 // Base Class 3 Sub-Class 0 Programming interface 0 - VGA compatible Display controller
762 //
763 VgaCompatible = TRUE;
764 }
765 }
766
767 return VgaCompatible;
768 }
769
770
771 EFI_STATUS
772 BiosVideoCheckForVbe (
773 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
774 )
775 /*++
776
777 Routine Description:
778
779 Check for VBE device
780
781 Arguments:
782
783 BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
784
785 Returns:
786
787 EFI_SUCCESS - VBE device found
788
789 --*/
790 {
791 EFI_STATUS Status;
792 EFI_IA32_REGISTER_SET Regs;
793 UINT16 *ModeNumberPtr;
794 BOOLEAN ModeFound;
795 BIOS_VIDEO_MODE_DATA *ModeBuffer;
796 UINTN Index;
797
798 //
799 // Allocate buffer under 1MB for VBE data structures
800 //
801 BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
802 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) + sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
803 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
804 );
805
806 BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
807
808 Status = gBS->AllocatePages (
809 AllocateMaxAddress,
810 EfiBootServicesData,
811 BiosVideoPrivate->NumberOfPagesBelow1MB,
812 &BiosVideoPrivate->PagesBelow1MB
813 );
814 if (EFI_ERROR (Status)) {
815 return Status;
816 }
817 //
818 // Fill in the UGA Draw Protocol
819 //
820 BiosVideoPrivate->UgaDraw.GetMode = BiosVideoUgaDrawGetMode;
821 BiosVideoPrivate->UgaDraw.SetMode = BiosVideoUgaDrawSetMode;
822 BiosVideoPrivate->UgaDraw.Blt = BiosVideoUgaDrawVbeBlt;
823
824 //
825 // Fill in the VBE related data structures
826 //
827 BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
828 BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
829 BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
830 BiosVideoPrivate->VbeSaveRestorePages = 0;
831 BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
832
833 //
834 // Test to see if the Video Adapter is compliant with VBE 3.0
835 //
836 gBS->SetMem (&Regs, sizeof (Regs), 0);
837 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
838 gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
839 BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
840 Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeInformationBlock);
841 Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeInformationBlock);
842
843 LegacyBiosInt86 (0x10, &Regs);
844
845 Status = EFI_DEVICE_ERROR;
846
847 //
848 // See if the VESA call succeeded
849 //
850 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
851 return Status;
852 }
853 //
854 // Check for 'VESA' signature
855 //
856 if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
857 return Status;
858 }
859 //
860 // Check to see if this is VBE 2.0 or higher
861 //
862 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
863 return Status;
864 }
865 //
866 // Walk through the mode list to see if there is at least one mode the is compatible with the UGA_DRAW protocol
867 //
868 ModeNumberPtr = (UINT16 *)
869 (
870 (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
871 ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
872 );
873 for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {
874 //
875 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
876 //
877 if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
878 continue;
879 }
880 //
881 // Get the information about the mode
882 //
883 gBS->SetMem (&Regs, sizeof (Regs), 0);
884 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
885 Regs.X.CX = *ModeNumberPtr;
886 gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
887 Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeModeInformationBlock);
888 Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeModeInformationBlock);
889
890 LegacyBiosInt86 (0x10, &Regs);
891
892 //
893 // See if the call succeeded. If it didn't, then try the next mode.
894 //
895 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
896 continue;
897 }
898 //
899 // See if the mode supports color. If it doesn't then try the next mode.
900 //
901 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
902 continue;
903 }
904 //
905 // See if the mode supports graphics. If it doesn't then try the next mode.
906 //
907 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
908 continue;
909 }
910 //
911 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
912 //
913 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
914 continue;
915 }
916 //
917 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
918 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
919 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
920 //
921 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
922 continue;
923 }
924
925 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
926 continue;
927 }
928
929 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
930 continue;
931 }
932 //
933 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
934 //
935 if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
936 continue;
937 }
938 //
939 // See if the resolution is 1024x768, 800x600, or 640x480
940 //
941 ModeFound = FALSE;
942 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
943 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
944 ) {
945 ModeFound = TRUE;
946 }
947
948 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
949 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
950 ) {
951 ModeFound = TRUE;
952 }
953
954 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
955 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
956 ) {
957 ModeFound = TRUE;
958 }
959
960 if (!ModeFound) {
961 continue;
962 }
963 //
964 // Add mode to the list of available modes
965 //
966 BiosVideoPrivate->MaxMode++;
967 Status = gBS->AllocatePool (
968 EfiBootServicesData,
969 BiosVideoPrivate->MaxMode * sizeof (BIOS_VIDEO_MODE_DATA),
970 (VOID **) &ModeBuffer
971 );
972 if (EFI_ERROR (Status)) {
973 goto Done;
974 }
975
976 if (BiosVideoPrivate->MaxMode > 1) {
977 gBS->CopyMem (
978 ModeBuffer,
979 BiosVideoPrivate->ModeData,
980 (BiosVideoPrivate->MaxMode - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
981 );
982 }
983
984 if (BiosVideoPrivate->ModeData != NULL) {
985 gBS->FreePool (BiosVideoPrivate->ModeData);
986 }
987
988 ModeBuffer[BiosVideoPrivate->MaxMode - 1].VbeModeNumber = *ModeNumberPtr;
989 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
990 ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
991 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
992 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
993 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
994 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
995 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
996 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
997
998 } else {
999 ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1000 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1001 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1002 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1003 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1004 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1005 ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1006
1007 }
1008
1009 ModeBuffer[BiosVideoPrivate->MaxMode - 1].LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1010 ModeBuffer[BiosVideoPrivate->MaxMode - 1].HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1011 ModeBuffer[BiosVideoPrivate->MaxMode - 1].VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1012
1013 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel >= 24) {
1014 ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = 32;
1015 } else {
1016 ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1017 }
1018
1019 ModeBuffer[BiosVideoPrivate->MaxMode - 1].BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1020
1021 ModeBuffer[BiosVideoPrivate->MaxMode - 1].RefreshRate = 60;
1022
1023 BiosVideoPrivate->ModeData = ModeBuffer;
1024 }
1025 //
1026 // Check to see if we found any modes that are compatible with UGA DRAW
1027 //
1028 if (BiosVideoPrivate->MaxMode == 0) {
1029 Status = EFI_DEVICE_ERROR;
1030 goto Done;
1031 }
1032 //
1033 // Find the best mode to initialize
1034 //
1035 Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 1024, 768, 32, 60);
1036 //Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 800, 600, 32, 60);
1037 if (EFI_ERROR (Status)) {
1038 Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 800, 600, 32, 60);
1039 //Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 1024, 768, 32, 60);
1040 if (EFI_ERROR (Status)) {
1041 Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 640, 480, 32, 60);
1042 for (Index = 0; EFI_ERROR (Status) && Index < BiosVideoPrivate->MaxMode; Index++) {
1043 Status = BiosVideoUgaDrawSetMode (
1044 &BiosVideoPrivate->UgaDraw,
1045 BiosVideoPrivate->ModeData[Index].HorizontalResolution,
1046 BiosVideoPrivate->ModeData[Index].VerticalResolution,
1047 BiosVideoPrivate->ModeData[Index].ColorDepth,
1048 BiosVideoPrivate->ModeData[Index].RefreshRate
1049 );
1050 }
1051 }
1052 }
1053
1054 Done:
1055 //
1056 // If there was an error, then free the mode structure
1057 //
1058 if (EFI_ERROR (Status)) {
1059 if (BiosVideoPrivate->ModeData != NULL) {
1060 gBS->FreePool (BiosVideoPrivate->ModeData);
1061 BiosVideoPrivate->ModeData = NULL;
1062 BiosVideoPrivate->MaxMode = 0;
1063 }
1064 }
1065
1066 return Status;
1067 }
1068
1069 EFI_STATUS
1070 BiosVideoCheckForVga (
1071 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1072 )
1073 /*++
1074
1075 Routine Description:
1076
1077 Check for VGA device
1078
1079 Arguments:
1080
1081 BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
1082
1083 Returns:
1084
1085 EFI_SUCCESS - Standard VGA device found
1086
1087 --*/
1088 {
1089 EFI_STATUS Status;
1090 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1091
1092 //
1093 // Fill in the UGA Draw Protocol
1094 //
1095 BiosVideoPrivate->UgaDraw.GetMode = BiosVideoUgaDrawGetMode;
1096 BiosVideoPrivate->UgaDraw.SetMode = BiosVideoUgaDrawSetMode;
1097 BiosVideoPrivate->UgaDraw.Blt = BiosVideoUgaDrawVgaBlt;
1098
1099 //
1100 // Add mode to the list of available modes
1101 //
1102 BiosVideoPrivate->MaxMode++;
1103 Status = gBS->AllocatePool (
1104 EfiBootServicesData,
1105 BiosVideoPrivate->MaxMode * sizeof (BIOS_VIDEO_MODE_DATA),
1106 (VOID **) &ModeBuffer
1107 );
1108 if (EFI_ERROR (Status)) {
1109 return Status;
1110 }
1111
1112 if (BiosVideoPrivate->MaxMode > 1) {
1113 gBS->CopyMem (
1114 ModeBuffer,
1115 BiosVideoPrivate->ModeData,
1116 (BiosVideoPrivate->MaxMode - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1117 );
1118 }
1119
1120 if (BiosVideoPrivate->ModeData != NULL) {
1121 gBS->FreePool (BiosVideoPrivate->ModeData);
1122 }
1123
1124 ModeBuffer[BiosVideoPrivate->MaxMode - 1].VbeModeNumber = 0x0012;
1125 ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = 640;
1126 ModeBuffer[BiosVideoPrivate->MaxMode - 1].LinearFrameBuffer = (VOID *) (UINTN)(0xa0000);
1127 ModeBuffer[BiosVideoPrivate->MaxMode - 1].HorizontalResolution = 640;
1128 ModeBuffer[BiosVideoPrivate->MaxMode - 1].VerticalResolution = 480;
1129 ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = 32;
1130 ModeBuffer[BiosVideoPrivate->MaxMode - 1].RefreshRate = 60;
1131
1132 BiosVideoPrivate->ModeData = ModeBuffer;
1133
1134 //
1135 // Test to see if the Video Adapter support the 640x480 16 color mode
1136 //
1137 Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 640, 480, 32, 60);
1138
1139 //
1140 // If there was an error, then free the mode structure
1141 //
1142 if (EFI_ERROR (Status)) {
1143 BiosVideoPrivate->MaxMode = 0;
1144 if (BiosVideoPrivate->ModeData != NULL) {
1145 gBS->FreePool (BiosVideoPrivate->ModeData);
1146 }
1147 }
1148
1149 return Status;
1150 }
1151 //
1152 // UGA Protocol Member Functions for VESA BIOS Extensions
1153 //
1154 EFI_STATUS
1155 EFIAPI
1156 BiosVideoUgaDrawGetMode (
1157 IN EFI_UGA_DRAW_PROTOCOL *This,
1158 OUT UINT32 *HorizontalResolution,
1159 OUT UINT32 *VerticalResolution,
1160 OUT UINT32 *ColorDepth,
1161 OUT UINT32 *RefreshRate
1162 )
1163 /*++
1164
1165 Routine Description:
1166
1167 UGA protocol interface to get video mode
1168
1169 Arguments:
1170
1171 This - Pointer to UGA draw protocol instance
1172 HorizontalResolution - Horizontal Resolution, in pixels
1173 VerticalResolution - Vertical Resolution, in pixels
1174 ColorDepth - Bit number used to represent color value of a pixel
1175 RefreshRate - Refresh rate, in Hertz
1176
1177 Returns:
1178
1179 EFI_DEVICE_ERROR - Hardware need starting
1180 EFI_INVALID_PARAMETER - Invalid parameter passed in
1181 EFI_SUCCESS - Video mode query successfully
1182
1183 --*/
1184 {
1185 BIOS_VIDEO_DEV *BiosVideoPrivate;
1186
1187 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
1188
1189 if (BiosVideoPrivate->HardwareNeedsStarting) {
1190 return EFI_DEVICE_ERROR;
1191 }
1192
1193 if (HorizontalResolution == NULL || VerticalResolution == NULL || ColorDepth == NULL || RefreshRate == NULL) {
1194 return EFI_INVALID_PARAMETER;
1195 }
1196
1197 *HorizontalResolution = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution;
1198 *VerticalResolution = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution;
1199 *ColorDepth = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].ColorDepth;
1200 *RefreshRate = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].RefreshRate;
1201
1202 return EFI_SUCCESS;
1203 }
1204
1205 EFI_STATUS
1206 EFIAPI
1207 BiosVideoUgaDrawSetMode (
1208 IN EFI_UGA_DRAW_PROTOCOL *This,
1209 IN UINT32 HorizontalResolution,
1210 IN UINT32 VerticalResolution,
1211 IN UINT32 ColorDepth,
1212 IN UINT32 RefreshRate
1213 )
1214 /*++
1215
1216 Routine Description:
1217
1218 UGA draw protocol interface to set video mode
1219
1220 Arguments:
1221
1222 This - Pointer to UGA draw protocol instance
1223 HorizontalResolution - Horizontal Resolution, in pixels
1224 VerticalResolution - Vertical Resolution, in pixels
1225 ColorDepth - Bit number used to represent color value of a pixel
1226 RefreshRate - Refresh rate, in Hertz
1227
1228 Returns:
1229
1230 EFI_DEVICE_ERROR - Device error
1231 EFI_SUCCESS - Video mode set successfully
1232 EFI_UNSUPPORTED - Cannot support this video mode
1233
1234 --*/
1235 {
1236 EFI_STATUS Status;
1237 BIOS_VIDEO_DEV *BiosVideoPrivate;
1238 UINTN Index;
1239 EFI_IA32_REGISTER_SET Regs;
1240
1241 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
1242
1243 for (Index = 0; Index < BiosVideoPrivate->MaxMode; Index++) {
1244
1245 if (HorizontalResolution != BiosVideoPrivate->ModeData[Index].HorizontalResolution) {
1246 continue;
1247 }
1248
1249 if (VerticalResolution != BiosVideoPrivate->ModeData[Index].VerticalResolution) {
1250 continue;
1251 }
1252
1253 if (ColorDepth != BiosVideoPrivate->ModeData[Index].ColorDepth) {
1254 continue;
1255 }
1256
1257 if (RefreshRate != BiosVideoPrivate->ModeData[Index].RefreshRate) {
1258 continue;
1259 }
1260
1261 if (BiosVideoPrivate->LineBuffer) {
1262 gBS->FreePool (BiosVideoPrivate->LineBuffer);
1263 }
1264
1265 if (BiosVideoPrivate->VgaFrameBuffer) {
1266 gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer);
1267 }
1268
1269 if (BiosVideoPrivate->VbeFrameBuffer) {
1270 gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer);
1271 }
1272
1273 BiosVideoPrivate->LineBuffer = NULL;
1274 Status = gBS->AllocatePool (
1275 EfiBootServicesData,
1276 BiosVideoPrivate->ModeData[Index].BytesPerScanLine,
1277 &BiosVideoPrivate->LineBuffer
1278 );
1279 if (EFI_ERROR (Status)) {
1280 return Status;
1281 }
1282 //
1283 // Clear all registers
1284 //
1285 gBS->SetMem (&Regs, sizeof (Regs), 0);
1286
1287 if (BiosVideoPrivate->ModeData[Index].VbeModeNumber < 0x100) {
1288 //
1289 // Allocate a working buffer for BLT operations to the VGA frame buffer
1290 //
1291 BiosVideoPrivate->VgaFrameBuffer = NULL;
1292 Status = gBS->AllocatePool (
1293 EfiBootServicesData,
1294 4 * 480 * 80,
1295 &BiosVideoPrivate->VgaFrameBuffer
1296 );
1297 if (EFI_ERROR (Status)) {
1298 return Status;
1299 }
1300 //
1301 // Set VGA Mode
1302 //
1303 Regs.X.AX = BiosVideoPrivate->ModeData[Index].VbeModeNumber;
1304 LegacyBiosInt86 (0x10, &Regs);
1305
1306 } else {
1307 //
1308 // Allocate a working buffer for BLT operations to the VBE frame buffer
1309 //
1310 BiosVideoPrivate->VbeFrameBuffer = NULL;
1311 Status = gBS->AllocatePool (
1312 EfiBootServicesData,
1313 BiosVideoPrivate->ModeData[Index].BytesPerScanLine * BiosVideoPrivate->ModeData[Index].VerticalResolution,
1314 &BiosVideoPrivate->VbeFrameBuffer
1315 );
1316 if (EFI_ERROR (Status)) {
1317 return Status;
1318 }
1319 //
1320 // Set VBE mode
1321 //
1322 Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
1323 Regs.X.BX = (UINT16) (BiosVideoPrivate->ModeData[Index].VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
1324 gBS->SetMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK), 0);
1325 Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock);
1326 Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock);
1327 LegacyBiosInt86 (0x10, &Regs);
1328
1329 //
1330 // Check to see if the call succeeded
1331 //
1332 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1333 return EFI_DEVICE_ERROR;
1334 }
1335 //
1336 // Initialize the state of the VbeFrameBuffer
1337 //
1338 Status = BiosVideoPrivate->PciIo->Mem.Read (
1339 BiosVideoPrivate->PciIo,
1340 EfiPciIoWidthUint32,
1341 EFI_PCI_IO_PASS_THROUGH_BAR,
1342 (UINT64) (UINTN) BiosVideoPrivate->ModeData[Index].LinearFrameBuffer,
1343 (BiosVideoPrivate->ModeData[Index].BytesPerScanLine * BiosVideoPrivate->ModeData[Index].VerticalResolution) >> 2,
1344 BiosVideoPrivate->VbeFrameBuffer
1345 );
1346 if (EFI_ERROR (Status)) {
1347 return Status;
1348 }
1349 }
1350
1351 BiosVideoPrivate->CurrentMode = Index;
1352
1353 BiosVideoPrivate->HardwareNeedsStarting = FALSE;
1354
1355 return EFI_SUCCESS;
1356 }
1357
1358 return EFI_UNSUPPORTED;
1359 }
1360
1361 VOID
1362 CopyVideoBuffer (
1363 IN EFI_PCI_IO_PROTOCOL *PciIo,
1364 IN UINT8 *VbeBuffer,
1365 IN VOID *MemAddress,
1366 IN UINTN DestinationX,
1367 IN UINTN DestinationY,
1368 IN UINTN TotalBytes,
1369 IN UINT32 VbePixelWidth,
1370 IN UINTN BytesPerScanLine
1371 )
1372 /*++
1373
1374 Routine Description:
1375
1376 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
1377
1378 Arguments:
1379
1380 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
1381 VbeBuffer - The data to transfer to screen
1382 MemAddress - Physical frame buffer base address
1383 DestinationX - The X coordinate of the destination for BltOperation
1384 DestinationY - The Y coordinate of the destination for BltOperation
1385 TotalBytes - The total bytes of copy
1386 VbePixelWidth - Bytes per pixel
1387 BytesPerScanLine - Bytes per scan line
1388
1389 Returns:
1390
1391 None.
1392
1393 --*/
1394 {
1395 UINTN FrameBufferAddr;
1396 UINTN CopyBlockNum;
1397 UINTN RemainingBytes;
1398 UINTN UnalignedBytes;
1399 EFI_STATUS Status;
1400
1401 FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
1402
1403 //
1404 // If TotalBytes is less than 4 bytes, only start byte copy.
1405 //
1406 if (TotalBytes < 4) {
1407 Status = PciIo->Mem.Write (
1408 PciIo,
1409 EfiPciIoWidthUint8,
1410 EFI_PCI_IO_PASS_THROUGH_BAR,
1411 (UINT64) FrameBufferAddr,
1412 TotalBytes,
1413 VbeBuffer
1414 );
1415 ASSERT_EFI_ERROR (Status);
1416 return;
1417 }
1418
1419 //
1420 // If VbeBuffer is not 4-byte aligned, start byte copy.
1421 //
1422 UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
1423
1424 if (UnalignedBytes != 0) {
1425 Status = PciIo->Mem.Write (
1426 PciIo,
1427 EfiPciIoWidthUint8,
1428 EFI_PCI_IO_PASS_THROUGH_BAR,
1429 (UINT64) FrameBufferAddr,
1430 UnalignedBytes,
1431 VbeBuffer
1432 );
1433 ASSERT_EFI_ERROR (Status);
1434 FrameBufferAddr += UnalignedBytes;
1435 VbeBuffer += UnalignedBytes;
1436 }
1437
1438 //
1439 // Calculate 4-byte block count and remaining bytes.
1440 //
1441 CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
1442 RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
1443
1444 //
1445 // Copy 4-byte block and remaining bytes to physical frame buffer.
1446 //
1447 if (CopyBlockNum != 0) {
1448 Status = PciIo->Mem.Write (
1449 PciIo,
1450 EfiPciIoWidthUint32,
1451 EFI_PCI_IO_PASS_THROUGH_BAR,
1452 (UINT64) FrameBufferAddr,
1453 CopyBlockNum,
1454 VbeBuffer
1455 );
1456 ASSERT_EFI_ERROR (Status);
1457 }
1458
1459 if (RemainingBytes != 0) {
1460 FrameBufferAddr += (CopyBlockNum << 2);
1461 VbeBuffer += (CopyBlockNum << 2);
1462 Status = PciIo->Mem.Write (
1463 PciIo,
1464 EfiPciIoWidthUint8,
1465 EFI_PCI_IO_PASS_THROUGH_BAR,
1466 (UINT64) FrameBufferAddr,
1467 RemainingBytes,
1468 VbeBuffer
1469 );
1470 ASSERT_EFI_ERROR (Status);
1471 }
1472 }
1473
1474 //
1475 // BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes
1476 //
1477 EFI_STATUS
1478 EFIAPI
1479 BiosVideoUgaDrawVbeBlt (
1480 IN EFI_UGA_DRAW_PROTOCOL *This,
1481 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
1482 IN EFI_UGA_BLT_OPERATION BltOperation,
1483 IN UINTN SourceX,
1484 IN UINTN SourceY,
1485 IN UINTN DestinationX,
1486 IN UINTN DestinationY,
1487 IN UINTN Width,
1488 IN UINTN Height,
1489 IN UINTN Delta
1490 )
1491 /*++
1492
1493 Routine Description:
1494
1495 UGA draw protocol instance to block transfer for VBE device
1496
1497 Arguments:
1498
1499 This - Pointer to UGA draw protocol instance
1500 BltBuffer - The data to transfer to screen
1501 BltOperation - The operation to perform
1502 SourceX - The X coordinate of the source for BltOperation
1503 SourceY - The Y coordinate of the source for BltOperation
1504 DestinationX - The X coordinate of the destination for BltOperation
1505 DestinationY - The Y coordinate of the destination for BltOperation
1506 Width - The width of a rectangle in the blt rectangle in pixels
1507 Height - The height of a rectangle in the blt rectangle in pixels
1508 Delta - Not used for EfiUgaVideoFill and EfiUgaVideoToVideo operation.
1509 If a Delta of 0 is used, the entire BltBuffer will be operated on.
1510 If a subrectangle of the BltBuffer is used, then Delta represents
1511 the number of bytes in a row of the BltBuffer.
1512
1513 Returns:
1514
1515 EFI_INVALID_PARAMETER - Invalid parameter passed in
1516 EFI_SUCCESS - Blt operation success
1517
1518 --*/
1519 {
1520 BIOS_VIDEO_DEV *BiosVideoPrivate;
1521 BIOS_VIDEO_MODE_DATA *Mode;
1522 EFI_PCI_IO_PROTOCOL *PciIo;
1523 EFI_TPL OriginalTPL;
1524 UINTN DstY;
1525 UINTN SrcY;
1526 UINTN DstX;
1527 EFI_UGA_PIXEL *Blt;
1528 VOID *MemAddress;
1529 EFI_UGA_PIXEL *VbeFrameBuffer;
1530 UINTN BytesPerScanLine;
1531 UINTN Index;
1532 UINT8 *VbeBuffer;
1533 UINT8 *VbeBuffer1;
1534 UINT8 *BltUint8;
1535 UINT32 VbePixelWidth;
1536 UINT32 Pixel;
1537 UINTN TotalBytes;
1538
1539 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
1540 Mode = &BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode];
1541 PciIo = BiosVideoPrivate->PciIo;
1542
1543 VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
1544 MemAddress = Mode->LinearFrameBuffer;
1545 BytesPerScanLine = Mode->BytesPerScanLine;
1546 VbePixelWidth = Mode->BitsPerPixel / 8;
1547 BltUint8 = (UINT8 *) BltBuffer;
1548 TotalBytes = Width * VbePixelWidth;
1549
1550 if ((BltOperation < EfiUgaVideoFill) || (BltOperation >= EfiUgaBltMax)) {
1551 return EFI_INVALID_PARAMETER;
1552 }
1553
1554 if (Width == 0 || Height == 0) {
1555 return EFI_INVALID_PARAMETER;
1556 }
1557 //
1558 // We need to fill the Virtual Screen buffer with the blt data.
1559 // The virtual screen is upside down, as the first row is the bootom row of
1560 // the image.
1561 //
1562 if (BltOperation == EfiUgaVideoToBltBuffer) {
1563 //
1564 // Video to BltBuffer: Source is Video, destination is BltBuffer
1565 //
1566 if (SourceY + Height > Mode->VerticalResolution) {
1567 return EFI_INVALID_PARAMETER;
1568 }
1569
1570 if (SourceX + Width > Mode->HorizontalResolution) {
1571 return EFI_INVALID_PARAMETER;
1572 }
1573 } else {
1574 //
1575 // BltBuffer to Video: Source is BltBuffer, destination is Video
1576 //
1577 if (DestinationY + Height > Mode->VerticalResolution) {
1578 return EFI_INVALID_PARAMETER;
1579 }
1580
1581 if (DestinationX + Width > Mode->HorizontalResolution) {
1582 return EFI_INVALID_PARAMETER;
1583 }
1584 }
1585 //
1586 // If Delta is zero, then the entire BltBuffer is being used, so Delta
1587 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
1588 // the number of bytes in each row can be computed.
1589 //
1590 if (Delta == 0) {
1591 Delta = Width * sizeof (EFI_UGA_PIXEL);
1592 }
1593 //
1594 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
1595 // We would not want a timer based event (Cursor, ...) to come in while we are
1596 // doing this operation.
1597 //
1598 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
1599
1600 switch (BltOperation) {
1601 case EfiUgaVideoToBltBuffer:
1602 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
1603 Blt = (EFI_UGA_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL));
1604 //
1605 // Shuffle the packed bytes in the hardware buffer to match EFI_UGA_PIXEL
1606 //
1607 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
1608 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
1609 Pixel = *(UINT32 *) (VbeBuffer);
1610 Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
1611 Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
1612 Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
1613 Blt->Reserved = 0;
1614 Blt++;
1615 VbeBuffer += VbePixelWidth;
1616 }
1617
1618 }
1619 break;
1620
1621 case EfiUgaVideoToVideo:
1622 for (Index = 0; Index < Height; Index++) {
1623 if (DestinationY <= SourceY) {
1624 SrcY = SourceY + Index;
1625 DstY = DestinationY + Index;
1626 } else {
1627 SrcY = SourceY + Height - Index - 1;
1628 DstY = DestinationY + Height - Index - 1;
1629 }
1630
1631 VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
1632 VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
1633
1634 gBS->CopyMem (
1635 VbeBuffer,
1636 VbeBuffer1,
1637 TotalBytes
1638 );
1639
1640 //
1641 // Update physical frame buffer.
1642 //
1643 CopyVideoBuffer (
1644 PciIo,
1645 VbeBuffer,
1646 MemAddress,
1647 DestinationX,
1648 DstY,
1649 TotalBytes,
1650 VbePixelWidth,
1651 BytesPerScanLine
1652 );
1653 }
1654 break;
1655
1656 case EfiUgaVideoFill:
1657 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
1658 Blt = (EFI_UGA_PIXEL *) BltUint8;
1659 //
1660 // Shuffle the RGB fields in EFI_UGA_PIXEL to match the hardware buffer
1661 //
1662 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
1663 (
1664 (Blt->Green & Mode->Green.Mask) <<
1665 Mode->Green.Position
1666 ) |
1667 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
1668
1669 for (Index = 0; Index < Width; Index++) {
1670 gBS->CopyMem (
1671 VbeBuffer,
1672 &Pixel,
1673 VbePixelWidth
1674 );
1675 VbeBuffer += VbePixelWidth;
1676 }
1677
1678 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
1679 for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
1680 gBS->CopyMem (
1681 (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
1682 VbeBuffer,
1683 TotalBytes
1684 );
1685 }
1686 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
1687 //
1688 // Update physical frame buffer.
1689 //
1690 CopyVideoBuffer (
1691 PciIo,
1692 VbeBuffer,
1693 MemAddress,
1694 DestinationX,
1695 DstY,
1696 TotalBytes,
1697 VbePixelWidth,
1698 BytesPerScanLine
1699 );
1700 }
1701
1702 break;
1703
1704 case EfiUgaBltBufferToVideo:
1705 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
1706 Blt = (EFI_UGA_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_UGA_PIXEL));
1707 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
1708 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
1709 //
1710 // Shuffle the RGB fields in EFI_UGA_PIXEL to match the hardware buffer
1711 //
1712 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
1713 ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
1714 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
1715 gBS->CopyMem (
1716 VbeBuffer,
1717 &Pixel,
1718 VbePixelWidth
1719 );
1720 Blt++;
1721 VbeBuffer += VbePixelWidth;
1722 }
1723
1724 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
1725
1726 //
1727 // Update physical frame buffer.
1728 //
1729 CopyVideoBuffer (
1730 PciIo,
1731 VbeBuffer,
1732 MemAddress,
1733 DestinationX,
1734 DstY,
1735 TotalBytes,
1736 VbePixelWidth,
1737 BytesPerScanLine
1738 );
1739 }
1740 break;
1741 }
1742
1743 gBS->RestoreTPL (OriginalTPL);
1744
1745 return EFI_SUCCESS;
1746 }
1747
1748 STATIC
1749 VOID
1750 WriteGraphicsController (
1751 IN EFI_PCI_IO_PROTOCOL *PciIo,
1752 IN UINTN Address,
1753 IN UINTN Data
1754 )
1755 /*++
1756
1757 Routine Description:
1758
1759 Write graphics controller registers
1760
1761 Arguments:
1762
1763 PciIo - Pointer to PciIo protocol instance of the controller
1764 Address - Register address
1765 Data - Data to be written to register
1766
1767 Returns:
1768
1769 None
1770
1771 --*/
1772 {
1773 Address = Address | (Data << 8);
1774 PciIo->Io.Write (
1775 PciIo,
1776 EfiPciIoWidthUint16,
1777 EFI_PCI_IO_PASS_THROUGH_BAR,
1778 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
1779 1,
1780 &Address
1781 );
1782 }
1783
1784 VOID
1785 VgaReadBitPlanes (
1786 EFI_PCI_IO_PROTOCOL *PciIo,
1787 UINT8 *HardwareBuffer,
1788 UINT8 *MemoryBuffer,
1789 UINTN WidthInBytes,
1790 UINTN Height
1791 )
1792 /*++
1793
1794 Routine Description:
1795
1796 Read the four bit plane of VGA frame buffer
1797
1798 Arguments:
1799
1800 PciIo - Pointer to PciIo protocol instance of the controller
1801 HardwareBuffer - Hardware VGA frame buffer address
1802 MemoryBuffer - Memory buffer address
1803 WidthInBytes - Number of bytes in a line to read
1804 Height - Height of the area to read
1805
1806 Returns:
1807
1808 None
1809
1810 --*/
1811 {
1812 UINTN BitPlane;
1813 UINTN Rows;
1814 UINTN FrameBufferOffset;
1815 UINT8 *Source;
1816 UINT8 *Destination;
1817
1818 //
1819 // Program the Mode Register Write mode 0, Read mode 0
1820 //
1821 WriteGraphicsController (
1822 PciIo,
1823 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
1824 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
1825 );
1826
1827 for (BitPlane = 0, FrameBufferOffset = 0;
1828 BitPlane < VGA_NUMBER_OF_BIT_PLANES;
1829 BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
1830 ) {
1831 //
1832 // Program the Read Map Select Register to select the correct bit plane
1833 //
1834 WriteGraphicsController (
1835 PciIo,
1836 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
1837 BitPlane
1838 );
1839
1840 Source = HardwareBuffer;
1841 Destination = MemoryBuffer + FrameBufferOffset;
1842
1843 for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
1844 PciIo->Mem.Read (
1845 PciIo,
1846 EfiPciIoWidthUint8,
1847 EFI_PCI_IO_PASS_THROUGH_BAR,
1848 (UINT64) Source,
1849 WidthInBytes,
1850 (VOID *) Destination
1851 );
1852 }
1853 }
1854 }
1855
1856 VOID
1857 VgaConvertToUgaColor (
1858 UINT8 *MemoryBuffer,
1859 UINTN X,
1860 UINTN Y,
1861 EFI_UGA_PIXEL *BltBuffer
1862 )
1863 /*++
1864
1865 Routine Description:
1866
1867 Internal routine to convert VGA color to UGA color
1868
1869 Arguments:
1870
1871 MemoryBuffer - Buffer containing VGA color
1872 X - The X coordinate of pixel on screen
1873 Y - The Y coordinate of pixel on screen
1874 BltBuffer - Buffer to contain converted UGA color
1875
1876 Returns:
1877
1878 None
1879
1880 --*/
1881 {
1882 UINTN Mask;
1883 UINTN Bit;
1884 UINTN Color;
1885
1886 MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3));
1887 Mask = mVgaBitMaskTable[X & 0x07];
1888 for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
1889 if (*MemoryBuffer & Mask) {
1890 Color |= Bit;
1891 }
1892 }
1893
1894 *BltBuffer = mVgaColorToUgaColor[Color];
1895 }
1896
1897 UINT8
1898 VgaConvertColor (
1899 IN EFI_UGA_PIXEL *BltBuffer
1900 )
1901 /*++
1902
1903 Routine Description:
1904
1905 Internal routine to convert UGA color to VGA color
1906
1907 Arguments:
1908
1909 BltBuffer - buffer containing UGA color
1910
1911 Returns:
1912
1913 Converted VGA color
1914
1915 --*/
1916 {
1917 UINT8 Color;
1918
1919 Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
1920 if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
1921 Color |= 0x08;
1922 }
1923
1924 return Color;
1925 }
1926
1927 EFI_STATUS
1928 EFIAPI
1929 BiosVideoUgaDrawVgaBlt (
1930 IN EFI_UGA_DRAW_PROTOCOL *This,
1931 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
1932 IN EFI_UGA_BLT_OPERATION BltOperation,
1933 IN UINTN SourceX,
1934 IN UINTN SourceY,
1935 IN UINTN DestinationX,
1936 IN UINTN DestinationY,
1937 IN UINTN Width,
1938 IN UINTN Height,
1939 IN UINTN Delta
1940 )
1941 /*++
1942
1943 Routine Description:
1944
1945 UGA draw protocol instance to block transfer for VGA device
1946
1947 Arguments:
1948
1949 This - Pointer to UGA draw protocol instance
1950 BltBuffer - The data to transfer to screen
1951 BltOperation - The operation to perform
1952 SourceX - The X coordinate of the source for BltOperation
1953 SourceY - The Y coordinate of the source for BltOperation
1954 DestinationX - The X coordinate of the destination for BltOperation
1955 DestinationY - The Y coordinate of the destination for BltOperation
1956 Width - The width of a rectangle in the blt rectangle in pixels
1957 Height - The height of a rectangle in the blt rectangle in pixels
1958 Delta - Not used for EfiUgaVideoFill and EfiUgaVideoToVideo operation.
1959 If a Delta of 0 is used, the entire BltBuffer will be operated on.
1960 If a subrectangle of the BltBuffer is used, then Delta represents
1961 the number of bytes in a row of the BltBuffer.
1962
1963 Returns:
1964
1965 EFI_INVALID_PARAMETER - Invalid parameter passed in
1966 EFI_SUCCESS - Blt operation success
1967
1968 --*/
1969 {
1970 BIOS_VIDEO_DEV *BiosVideoPrivate;
1971 EFI_TPL OriginalTPL;
1972 UINT8 *MemAddress;
1973 UINTN BytesPerScanLine;
1974 UINTN BytesPerBitPlane;
1975 UINTN Bit;
1976 UINTN Index;
1977 UINTN Index1;
1978 UINTN StartAddress;
1979 UINTN Bytes;
1980 UINTN Offset;
1981 UINT8 LeftMask;
1982 UINT8 RightMask;
1983 UINTN Address;
1984 UINTN AddressFix;
1985 UINT8 *Address1;
1986 UINT8 *SourceAddress;
1987 UINT8 *DestinationAddress;
1988 EFI_PCI_IO_PROTOCOL *PciIo;
1989 UINT8 Data;
1990 UINT8 PixelColor;
1991 UINT8 *VgaFrameBuffer;
1992 UINTN SourceOffset;
1993 UINTN SourceWidth;
1994 UINTN Rows;
1995 UINTN Columns;
1996 UINTN X;
1997 UINTN Y;
1998
1999 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
2000
2001 PciIo = BiosVideoPrivate->PciIo;
2002 MemAddress = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].LinearFrameBuffer;
2003 BytesPerScanLine = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].BytesPerScanLine >> 3;
2004 BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution;
2005 VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
2006
2007 if ((BltOperation < EfiUgaVideoFill) || (BltOperation >= EfiUgaBltMax)) {
2008 return EFI_INVALID_PARAMETER;
2009 }
2010
2011 if (Width == 0 || Height == 0) {
2012 return EFI_INVALID_PARAMETER;
2013 }
2014 //
2015 // We need to fill the Virtual Screen buffer with the blt data.
2016 // The virtual screen is upside down, as the first row is the bootom row of
2017 // the image.
2018 //
2019 if (BltOperation == EfiUgaVideoToBltBuffer) {
2020 //
2021 // Video to BltBuffer: Source is Video, destination is BltBuffer
2022 //
2023 if (SourceY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
2024 return EFI_INVALID_PARAMETER;
2025 }
2026
2027 if (SourceX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
2028 return EFI_INVALID_PARAMETER;
2029 }
2030 } else {
2031 //
2032 // BltBuffer to Video: Source is BltBuffer, destination is Video
2033 //
2034 if (DestinationY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
2035 return EFI_INVALID_PARAMETER;
2036 }
2037
2038 if (DestinationX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
2039 return EFI_INVALID_PARAMETER;
2040 }
2041 }
2042 //
2043 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2044 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2045 // the number of bytes in each row can be computed.
2046 //
2047 if (Delta == 0) {
2048 Delta = Width * sizeof (EFI_UGA_PIXEL);
2049 }
2050 //
2051 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2052 // We would not want a timer based event (Cursor, ...) to come in while we are
2053 // doing this operation.
2054 //
2055 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2056
2057 //
2058 // Compute some values we need for VGA
2059 //
2060 switch (BltOperation) {
2061 case EfiUgaVideoToBltBuffer:
2062
2063 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2064 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2065
2066 //
2067 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2068 //
2069 VgaReadBitPlanes (
2070 PciIo,
2071 MemAddress + SourceOffset,
2072 VgaFrameBuffer + SourceOffset,
2073 SourceWidth,
2074 Height
2075 );
2076
2077 //
2078 // Convert VGA Bit Planes to a UGA 32-bit color value
2079 //
2080 BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2081 for (Rows = 0, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) {
2082 for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) {
2083 VgaConvertToUgaColor (VgaFrameBuffer, X, Y, BltBuffer);
2084 }
2085
2086 BltBuffer -= Width;
2087 }
2088
2089 break;
2090
2091 case EfiUgaVideoToVideo:
2092 //
2093 // Check for an aligned Video to Video operation
2094 //
2095 if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2096 //
2097 // Program the Mode Register Write mode 1, Read mode 0
2098 //
2099 WriteGraphicsController (
2100 BiosVideoPrivate->PciIo,
2101 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2102 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2103 );
2104
2105 SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2106 DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2107 Bytes = Width >> 3;
2108 for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2109 PciIo->CopyMem (
2110 PciIo,
2111 EfiPciIoWidthUint8,
2112 EFI_PCI_IO_PASS_THROUGH_BAR,
2113 (UINT64) (DestinationAddress + Offset),
2114 EFI_PCI_IO_PASS_THROUGH_BAR,
2115 (UINT64) (SourceAddress + Offset),
2116 Bytes
2117 );
2118 }
2119 } else {
2120 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2121 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2122
2123 //
2124 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2125 //
2126 VgaReadBitPlanes (
2127 PciIo,
2128 MemAddress + SourceOffset,
2129 VgaFrameBuffer + SourceOffset,
2130 SourceWidth,
2131 Height
2132 );
2133 }
2134
2135 break;
2136
2137 case EfiUgaVideoFill:
2138 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2139 Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2140 LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
2141 RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2142 if (Bytes == 0) {
2143 LeftMask &= RightMask;
2144 RightMask = 0;
2145 }
2146
2147 if (LeftMask == 0xff) {
2148 StartAddress--;
2149 Bytes++;
2150 LeftMask = 0;
2151 }
2152
2153 if (RightMask == 0xff) {
2154 Bytes++;
2155 RightMask = 0;
2156 }
2157
2158 PixelColor = VgaConvertColor (BltBuffer);
2159
2160 //
2161 // Program the Mode Register Write mode 2, Read mode 0
2162 //
2163 WriteGraphicsController (
2164 BiosVideoPrivate->PciIo,
2165 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2166 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2167 );
2168
2169 //
2170 // Program the Data Rotate/Function Select Register to replace
2171 //
2172 WriteGraphicsController (
2173 BiosVideoPrivate->PciIo,
2174 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2175 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2176 );
2177
2178 if (LeftMask != 0) {
2179 //
2180 // Program the BitMask register with the Left column mask
2181 //
2182 WriteGraphicsController (
2183 BiosVideoPrivate->PciIo,
2184 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2185 LeftMask
2186 );
2187
2188 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2189 //
2190 // Read data from the bit planes into the latches
2191 //
2192 PciIo->Mem.Read (
2193 PciIo,
2194 EfiPciIoWidthUint8,
2195 EFI_PCI_IO_PASS_THROUGH_BAR,
2196 (UINT64) Address,
2197 1,
2198 &Data
2199 );
2200 //
2201 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2202 //
2203 PciIo->Mem.Write (
2204 PciIo,
2205 EfiPciIoWidthUint8,
2206 EFI_PCI_IO_PASS_THROUGH_BAR,
2207 (UINT64) Address,
2208 1,
2209 &PixelColor
2210 );
2211 }
2212 }
2213
2214 if (Bytes > 1) {
2215 //
2216 // Program the BitMask register with the middle column mask of 0xff
2217 //
2218 WriteGraphicsController (
2219 BiosVideoPrivate->PciIo,
2220 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2221 0xff
2222 );
2223
2224 for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
2225 PciIo->Mem.Write (
2226 PciIo,
2227 EfiPciIoWidthFillUint8,
2228 EFI_PCI_IO_PASS_THROUGH_BAR,
2229 (UINT64) Address,
2230 Bytes - 1,
2231 &PixelColor
2232 );
2233 }
2234 }
2235
2236 if (RightMask != 0) {
2237 //
2238 // Program the BitMask register with the Right column mask
2239 //
2240 WriteGraphicsController (
2241 BiosVideoPrivate->PciIo,
2242 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2243 RightMask
2244 );
2245
2246 for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
2247 //
2248 // Read data from the bit planes into the latches
2249 //
2250 PciIo->Mem.Read (
2251 PciIo,
2252 EfiPciIoWidthUint8,
2253 EFI_PCI_IO_PASS_THROUGH_BAR,
2254 (UINT64) Address,
2255 1,
2256 &Data
2257 );
2258 //
2259 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2260 //
2261 PciIo->Mem.Write (
2262 PciIo,
2263 EfiPciIoWidthUint8,
2264 EFI_PCI_IO_PASS_THROUGH_BAR,
2265 (UINT64) Address,
2266 1,
2267 &PixelColor
2268 );
2269 }
2270 }
2271 break;
2272
2273 case EfiUgaBltBufferToVideo:
2274 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2275 LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
2276
2277 //
2278 // Program the Mode Register Write mode 2, Read mode 0
2279 //
2280 WriteGraphicsController (
2281 BiosVideoPrivate->PciIo,
2282 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2283 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2284 );
2285
2286 //
2287 // Program the Data Rotate/Function Select Register to replace
2288 //
2289 WriteGraphicsController (
2290 BiosVideoPrivate->PciIo,
2291 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2292 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2293 );
2294
2295 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2296 for (Index1 = 0; Index1 < Width; Index1++) {
2297 BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
2298 }
2299 AddressFix = Address;
2300
2301 for (Bit = 0; Bit < 8; Bit++) {
2302 //
2303 // Program the BitMask register with the Left column mask
2304 //
2305 WriteGraphicsController (
2306 BiosVideoPrivate->PciIo,
2307 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2308 LeftMask
2309 );
2310
2311 for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
2312 //
2313 // Read data from the bit planes into the latches
2314 //
2315 PciIo->Mem.Read (
2316 PciIo,
2317 EfiPciIoWidthUint8,
2318 EFI_PCI_IO_PASS_THROUGH_BAR,
2319 (UINT64) Address1,
2320 1,
2321 &Data
2322 );
2323
2324 PciIo->Mem.Write (
2325 PciIo,
2326 EfiPciIoWidthUint8,
2327 EFI_PCI_IO_PASS_THROUGH_BAR,
2328 (UINT64) Address1,
2329 1,
2330 &BiosVideoPrivate->LineBuffer[Index1]
2331 );
2332 }
2333
2334 LeftMask = (UINT8) (LeftMask >> 1);
2335 if (LeftMask == 0) {
2336 LeftMask = 0x80;
2337 AddressFix++;
2338 }
2339 }
2340 }
2341
2342 break;
2343 }
2344
2345 gBS->RestoreTPL (OriginalTPL);
2346
2347 return EFI_SUCCESS;
2348 }
2349 //
2350 // VGA Mini Port Protocol Functions
2351 //
2352 EFI_STATUS
2353 EFIAPI
2354 BiosVideoVgaMiniPortSetMode (
2355 IN EFI_VGA_MINI_PORT_PROTOCOL *This,
2356 IN UINTN ModeNumber
2357 )
2358 /*++
2359
2360 Routine Description:
2361
2362 VgaMiniPort protocol interface to set mode
2363
2364 Arguments:
2365
2366 This - Pointer to VgaMiniPort protocol instance
2367 ModeNumber - The index of the mode
2368
2369 Returns:
2370
2371 EFI_UNSUPPORTED - The requested mode is not supported
2372 EFI_SUCCESS - The requested mode is set successfully
2373
2374 --*/
2375 {
2376 BIOS_VIDEO_DEV *BiosVideoPrivate;
2377 EFI_IA32_REGISTER_SET Regs;
2378
2379 //
2380 // Make sure the ModeNumber is a valid value
2381 //
2382 if (ModeNumber >= This->MaxMode) {
2383 return EFI_UNSUPPORTED;
2384 }
2385 //
2386 // Get the device structure for this device
2387 //
2388 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
2389
2390 gBS->SetMem (&Regs, sizeof (Regs), 0);
2391
2392 switch (ModeNumber) {
2393 case 0:
2394 //
2395 // Set the 80x25 Text VGA Mode
2396 //
2397 Regs.H.AH = 0x00;
2398 Regs.H.AL = 0x83;
2399 LegacyBiosInt86 (0x10, &Regs);
2400
2401 Regs.H.AH = 0x11;
2402 Regs.H.AL = 0x14;
2403 Regs.H.BL = 0;
2404 LegacyBiosInt86 (0x10, &Regs);
2405 break;
2406
2407 case 1:
2408 //
2409 // Set the 80x50 Text VGA Mode
2410 //
2411 Regs.H.AH = 0x00;
2412 Regs.H.AL = 0x83;
2413 LegacyBiosInt86 (0x10, &Regs);
2414 Regs.H.AH = 0x11;
2415 Regs.H.AL = 0x12;
2416 Regs.H.BL = 0;
2417 LegacyBiosInt86 (0x10, &Regs);
2418 break;
2419
2420 default:
2421 return EFI_UNSUPPORTED;
2422 }
2423
2424 return EFI_SUCCESS;
2425 }
2426
2427 VOID
2428 InitializeBiosIntCaller (
2429 VOID
2430 )
2431 {
2432 EFI_STATUS Status;
2433 UINT32 RealModeBufferSize;
2434 UINT32 ExtraStackSize;
2435 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
2436
2437 //
2438 // Get LegacyRegion
2439 //
2440 AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);
2441
2442 LegacyRegionBase = 0x100000;
2443 Status = gBS->AllocatePages (
2444 AllocateMaxAddress,
2445 EfiACPIMemoryNVS,
2446 EFI_SIZE_TO_PAGES(RealModeBufferSize + ExtraStackSize + 200),
2447 &LegacyRegionBase
2448 );
2449 ASSERT_EFI_ERROR (Status);
2450
2451 mThunkContext.RealModeBuffer = (VOID*)(UINTN)LegacyRegionBase;
2452 mThunkContext.RealModeBufferSize = EFI_PAGES_TO_SIZE (RealModeBufferSize);
2453 mThunkContext.ThunkAttributes = 3;
2454 AsmPrepareThunk16(&mThunkContext);
2455
2456 //Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
2457 //ASSERT_EFI_ERROR (Status);
2458 }
2459
2460 VOID
2461 InitializeInterruptRedirection (
2462 VOID
2463 )
2464 /*++
2465
2466 Routine Description:
2467 Initialize interrupt redirection code and entries, because
2468 IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
2469 Or the interrupt will lost when we do thunk.
2470 NOTE: We do not reset 8259 vector base, because it will cause pending
2471 interrupt lost.
2472
2473 Arguments:
2474 NONE
2475
2476 Returns:
2477 NONE
2478 --*/
2479 {
2480 EFI_STATUS Status;
2481 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
2482 UINTN LegacyRegionLength;
2483 UINT32 *IdtArray;
2484 UINTN Index;
2485 UINT8 ProtectedModeBaseVector;
2486 UINT32 InterruptRedirectionCode[] = {
2487 0x90CF08CD, // INT8; IRET; NOP
2488 0x90CF09CD, // INT9; IRET; NOP
2489 0x90CF0ACD, // INTA; IRET; NOP
2490 0x90CF0BCD, // INTB; IRET; NOP
2491 0x90CF0CCD, // INTC; IRET; NOP
2492 0x90CF0DCD, // INTD; IRET; NOP
2493 0x90CF0ECD, // INTE; IRET; NOP
2494 0x90CF0FCD // INTF; IRET; NOP
2495 };
2496
2497 //
2498 // Get LegacyRegion
2499 //
2500 LegacyRegionLength = sizeof(InterruptRedirectionCode);
2501 LegacyRegionBase = 0x100000;
2502 Status = gBS->AllocatePages (
2503 AllocateMaxAddress,
2504 EfiACPIMemoryNVS,
2505 EFI_SIZE_TO_PAGES(LegacyRegionLength),
2506 &LegacyRegionBase
2507 );
2508 ASSERT_EFI_ERROR (Status);
2509
2510 //
2511 // Copy code to legacy region
2512 //
2513 CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));
2514
2515 //
2516 // Get VectorBase, it should be 0x68
2517 //
2518 Status = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, &ProtectedModeBaseVector);
2519 ASSERT_EFI_ERROR (Status);
2520
2521 //
2522 // Patch IVT 0x68 ~ 0x6f
2523 //
2524 IdtArray = (UINT32 *) 0;
2525 for (Index = 0; Index < 8; Index++) {
2526 IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));
2527 }
2528
2529 return ;
2530 }
2531
2532 BOOLEAN
2533 EFIAPI
2534 LegacyBiosInt86 (
2535 IN UINT8 BiosInt,
2536 IN EFI_IA32_REGISTER_SET *Regs
2537 )
2538 /*++
2539
2540 Routine Description:
2541 Thunk to 16-bit real mode and execute a software interrupt with a vector
2542 of BiosInt. Regs will contain the 16-bit register context on entry and
2543 exit.
2544
2545 Arguments:
2546 This - Protocol instance pointer.
2547 BiosInt - Processor interrupt vector to invoke
2548 Reg - Register contexted passed into (and returned) from thunk to
2549 16-bit mode
2550
2551 Returns:
2552 FALSE - Thunk completed, and there were no BIOS errors in the target code.
2553 See Regs for status.
2554 TRUE - There was a BIOS erro in the target code.
2555
2556 --*/
2557 {
2558 UINTN Status;
2559 UINT32 Eflags;
2560 IA32_REGISTER_SET ThunkRegSet;
2561 BOOLEAN Ret;
2562 UINT16 *Stack16;
2563
2564 Regs->X.Flags.Reserved1 = 1;
2565 Regs->X.Flags.Reserved2 = 0;
2566 Regs->X.Flags.Reserved3 = 0;
2567 Regs->X.Flags.Reserved4 = 0;
2568 Regs->X.Flags.IOPL = 3;
2569 Regs->X.Flags.NT = 0;
2570 Regs->X.Flags.IF = 1;
2571 Regs->X.Flags.TF = 0;
2572 Regs->X.Flags.CF = 0;
2573
2574 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
2575 ThunkRegSet.E.EDI = Regs->E.EDI;
2576 ThunkRegSet.E.ESI = Regs->E.ESI;
2577 ThunkRegSet.E.EBP = Regs->E.EBP;
2578 ThunkRegSet.E.EBX = Regs->E.EBX;
2579 ThunkRegSet.E.EDX = Regs->E.EDX;
2580 ThunkRegSet.E.ECX = Regs->E.ECX;
2581 ThunkRegSet.E.EAX = Regs->E.EAX;
2582 ThunkRegSet.E.DS = Regs->E.DS;
2583 ThunkRegSet.E.ES = Regs->E.ES;
2584
2585 CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32));
2586
2587 //
2588 // The call to Legacy16 is a critical section to EFI
2589 //
2590 Eflags = AsmReadEflags ();
2591 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
2592 DisableInterrupts ();
2593 }
2594
2595 //
2596 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
2597 //
2598 Status = mLegacy8259->SetMode (mLegacy8259, Efi8259LegacyMode, NULL, NULL);
2599 ASSERT_EFI_ERROR (Status);
2600
2601 Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
2602 Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16);
2603 CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS));
2604
2605 ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
2606 ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
2607 ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];
2608 ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);
2609 mThunkContext.RealModeState = &ThunkRegSet;
2610 AsmThunk16 (&mThunkContext);
2611
2612 //
2613 // Restore protected mode interrupt state
2614 //
2615 Status = mLegacy8259->SetMode (mLegacy8259, Efi8259ProtectedMode, NULL, NULL);
2616 ASSERT_EFI_ERROR (Status);
2617
2618 //
2619 // End critical section
2620 //
2621 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
2622 EnableInterrupts ();
2623 }
2624
2625 Regs->E.EDI = ThunkRegSet.E.EDI;
2626 Regs->E.ESI = ThunkRegSet.E.ESI;
2627 Regs->E.EBP = ThunkRegSet.E.EBP;
2628 Regs->E.EBX = ThunkRegSet.E.EBX;
2629 Regs->E.EDX = ThunkRegSet.E.EDX;
2630 Regs->E.ECX = ThunkRegSet.E.ECX;
2631 Regs->E.EAX = ThunkRegSet.E.EAX;
2632 Regs->E.SS = ThunkRegSet.E.SS;
2633 Regs->E.CS = ThunkRegSet.E.CS;
2634 Regs->E.DS = ThunkRegSet.E.DS;
2635 Regs->E.ES = ThunkRegSet.E.ES;
2636
2637 CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
2638
2639 Ret = (BOOLEAN) (Regs->E.EFlags.CF == 1);
2640
2641 return Ret;
2642 }
2643
2644