]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/BiosVideoThunkDxe/BiosVideo.c
Fix building issue for linux toolchain
[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 (VOID**)&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 (VOID**)&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 (VOID**)&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 (VOID**)&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 (VOID**)&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 default:
1742 break;
1743 }
1744
1745 gBS->RestoreTPL (OriginalTPL);
1746
1747 return EFI_SUCCESS;
1748 }
1749
1750 STATIC
1751 VOID
1752 WriteGraphicsController (
1753 IN EFI_PCI_IO_PROTOCOL *PciIo,
1754 IN UINTN Address,
1755 IN UINTN Data
1756 )
1757 /*++
1758
1759 Routine Description:
1760
1761 Write graphics controller registers
1762
1763 Arguments:
1764
1765 PciIo - Pointer to PciIo protocol instance of the controller
1766 Address - Register address
1767 Data - Data to be written to register
1768
1769 Returns:
1770
1771 None
1772
1773 --*/
1774 {
1775 Address = Address | (Data << 8);
1776 PciIo->Io.Write (
1777 PciIo,
1778 EfiPciIoWidthUint16,
1779 EFI_PCI_IO_PASS_THROUGH_BAR,
1780 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
1781 1,
1782 &Address
1783 );
1784 }
1785
1786 VOID
1787 VgaReadBitPlanes (
1788 EFI_PCI_IO_PROTOCOL *PciIo,
1789 UINT8 *HardwareBuffer,
1790 UINT8 *MemoryBuffer,
1791 UINTN WidthInBytes,
1792 UINTN Height
1793 )
1794 /*++
1795
1796 Routine Description:
1797
1798 Read the four bit plane of VGA frame buffer
1799
1800 Arguments:
1801
1802 PciIo - Pointer to PciIo protocol instance of the controller
1803 HardwareBuffer - Hardware VGA frame buffer address
1804 MemoryBuffer - Memory buffer address
1805 WidthInBytes - Number of bytes in a line to read
1806 Height - Height of the area to read
1807
1808 Returns:
1809
1810 None
1811
1812 --*/
1813 {
1814 UINTN BitPlane;
1815 UINTN Rows;
1816 UINTN FrameBufferOffset;
1817 UINT8 *Source;
1818 UINT8 *Destination;
1819
1820 //
1821 // Program the Mode Register Write mode 0, Read mode 0
1822 //
1823 WriteGraphicsController (
1824 PciIo,
1825 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
1826 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
1827 );
1828
1829 for (BitPlane = 0, FrameBufferOffset = 0;
1830 BitPlane < VGA_NUMBER_OF_BIT_PLANES;
1831 BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
1832 ) {
1833 //
1834 // Program the Read Map Select Register to select the correct bit plane
1835 //
1836 WriteGraphicsController (
1837 PciIo,
1838 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
1839 BitPlane
1840 );
1841
1842 Source = HardwareBuffer;
1843 Destination = MemoryBuffer + FrameBufferOffset;
1844
1845 for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
1846 PciIo->Mem.Read (
1847 PciIo,
1848 EfiPciIoWidthUint8,
1849 EFI_PCI_IO_PASS_THROUGH_BAR,
1850 (UINT64) (UINTN)Source,
1851 WidthInBytes,
1852 (VOID *) Destination
1853 );
1854 }
1855 }
1856 }
1857
1858 VOID
1859 VgaConvertToUgaColor (
1860 UINT8 *MemoryBuffer,
1861 UINTN X,
1862 UINTN Y,
1863 EFI_UGA_PIXEL *BltBuffer
1864 )
1865 /*++
1866
1867 Routine Description:
1868
1869 Internal routine to convert VGA color to UGA color
1870
1871 Arguments:
1872
1873 MemoryBuffer - Buffer containing VGA color
1874 X - The X coordinate of pixel on screen
1875 Y - The Y coordinate of pixel on screen
1876 BltBuffer - Buffer to contain converted UGA color
1877
1878 Returns:
1879
1880 None
1881
1882 --*/
1883 {
1884 UINTN Mask;
1885 UINTN Bit;
1886 UINTN Color;
1887
1888 MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3));
1889 Mask = mVgaBitMaskTable[X & 0x07];
1890 for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
1891 if (*MemoryBuffer & Mask) {
1892 Color |= Bit;
1893 }
1894 }
1895
1896 *BltBuffer = mVgaColorToUgaColor[Color];
1897 }
1898
1899 UINT8
1900 VgaConvertColor (
1901 IN EFI_UGA_PIXEL *BltBuffer
1902 )
1903 /*++
1904
1905 Routine Description:
1906
1907 Internal routine to convert UGA color to VGA color
1908
1909 Arguments:
1910
1911 BltBuffer - buffer containing UGA color
1912
1913 Returns:
1914
1915 Converted VGA color
1916
1917 --*/
1918 {
1919 UINT8 Color;
1920
1921 Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
1922 if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
1923 Color |= 0x08;
1924 }
1925
1926 return Color;
1927 }
1928
1929 EFI_STATUS
1930 EFIAPI
1931 BiosVideoUgaDrawVgaBlt (
1932 IN EFI_UGA_DRAW_PROTOCOL *This,
1933 IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
1934 IN EFI_UGA_BLT_OPERATION BltOperation,
1935 IN UINTN SourceX,
1936 IN UINTN SourceY,
1937 IN UINTN DestinationX,
1938 IN UINTN DestinationY,
1939 IN UINTN Width,
1940 IN UINTN Height,
1941 IN UINTN Delta
1942 )
1943 /*++
1944
1945 Routine Description:
1946
1947 UGA draw protocol instance to block transfer for VGA device
1948
1949 Arguments:
1950
1951 This - Pointer to UGA draw protocol instance
1952 BltBuffer - The data to transfer to screen
1953 BltOperation - The operation to perform
1954 SourceX - The X coordinate of the source for BltOperation
1955 SourceY - The Y coordinate of the source for BltOperation
1956 DestinationX - The X coordinate of the destination for BltOperation
1957 DestinationY - The Y coordinate of the destination for BltOperation
1958 Width - The width of a rectangle in the blt rectangle in pixels
1959 Height - The height of a rectangle in the blt rectangle in pixels
1960 Delta - Not used for EfiUgaVideoFill and EfiUgaVideoToVideo operation.
1961 If a Delta of 0 is used, the entire BltBuffer will be operated on.
1962 If a subrectangle of the BltBuffer is used, then Delta represents
1963 the number of bytes in a row of the BltBuffer.
1964
1965 Returns:
1966
1967 EFI_INVALID_PARAMETER - Invalid parameter passed in
1968 EFI_SUCCESS - Blt operation success
1969
1970 --*/
1971 {
1972 BIOS_VIDEO_DEV *BiosVideoPrivate;
1973 EFI_TPL OriginalTPL;
1974 UINT8 *MemAddress;
1975 UINTN BytesPerScanLine;
1976 UINTN BytesPerBitPlane;
1977 UINTN Bit;
1978 UINTN Index;
1979 UINTN Index1;
1980 UINTN StartAddress;
1981 UINTN Bytes;
1982 UINTN Offset;
1983 UINT8 LeftMask;
1984 UINT8 RightMask;
1985 UINTN Address;
1986 UINTN AddressFix;
1987 UINT8 *Address1;
1988 UINT8 *SourceAddress;
1989 UINT8 *DestinationAddress;
1990 EFI_PCI_IO_PROTOCOL *PciIo;
1991 UINT8 Data;
1992 UINT8 PixelColor;
1993 UINT8 *VgaFrameBuffer;
1994 UINTN SourceOffset;
1995 UINTN SourceWidth;
1996 UINTN Rows;
1997 UINTN Columns;
1998 UINTN X;
1999 UINTN Y;
2000
2001 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
2002
2003 PciIo = BiosVideoPrivate->PciIo;
2004 MemAddress = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].LinearFrameBuffer;
2005 BytesPerScanLine = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].BytesPerScanLine >> 3;
2006 BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution;
2007 VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
2008
2009 if ((BltOperation < EfiUgaVideoFill) || (BltOperation >= EfiUgaBltMax)) {
2010 return EFI_INVALID_PARAMETER;
2011 }
2012
2013 if (Width == 0 || Height == 0) {
2014 return EFI_INVALID_PARAMETER;
2015 }
2016 //
2017 // We need to fill the Virtual Screen buffer with the blt data.
2018 // The virtual screen is upside down, as the first row is the bootom row of
2019 // the image.
2020 //
2021 if (BltOperation == EfiUgaVideoToBltBuffer) {
2022 //
2023 // Video to BltBuffer: Source is Video, destination is BltBuffer
2024 //
2025 if (SourceY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
2026 return EFI_INVALID_PARAMETER;
2027 }
2028
2029 if (SourceX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
2030 return EFI_INVALID_PARAMETER;
2031 }
2032 } else {
2033 //
2034 // BltBuffer to Video: Source is BltBuffer, destination is Video
2035 //
2036 if (DestinationY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
2037 return EFI_INVALID_PARAMETER;
2038 }
2039
2040 if (DestinationX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
2041 return EFI_INVALID_PARAMETER;
2042 }
2043 }
2044 //
2045 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2046 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2047 // the number of bytes in each row can be computed.
2048 //
2049 if (Delta == 0) {
2050 Delta = Width * sizeof (EFI_UGA_PIXEL);
2051 }
2052 //
2053 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2054 // We would not want a timer based event (Cursor, ...) to come in while we are
2055 // doing this operation.
2056 //
2057 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2058
2059 //
2060 // Compute some values we need for VGA
2061 //
2062 switch (BltOperation) {
2063 case EfiUgaVideoToBltBuffer:
2064
2065 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2066 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2067
2068 //
2069 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2070 //
2071 VgaReadBitPlanes (
2072 PciIo,
2073 MemAddress + SourceOffset,
2074 VgaFrameBuffer + SourceOffset,
2075 SourceWidth,
2076 Height
2077 );
2078
2079 //
2080 // Convert VGA Bit Planes to a UGA 32-bit color value
2081 //
2082 BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2083 for (Rows = 0, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) {
2084 for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) {
2085 VgaConvertToUgaColor (VgaFrameBuffer, X, Y, BltBuffer);
2086 }
2087
2088 BltBuffer -= Width;
2089 }
2090
2091 break;
2092
2093 case EfiUgaVideoToVideo:
2094 //
2095 // Check for an aligned Video to Video operation
2096 //
2097 if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2098 //
2099 // Program the Mode Register Write mode 1, Read mode 0
2100 //
2101 WriteGraphicsController (
2102 BiosVideoPrivate->PciIo,
2103 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2104 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2105 );
2106
2107 SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2108 DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2109 Bytes = Width >> 3;
2110 for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2111 PciIo->CopyMem (
2112 PciIo,
2113 EfiPciIoWidthUint8,
2114 EFI_PCI_IO_PASS_THROUGH_BAR,
2115 (UINT64) ((UINTN)DestinationAddress + Offset),
2116 EFI_PCI_IO_PASS_THROUGH_BAR,
2117 (UINT64) ((UINTN)SourceAddress + Offset),
2118 Bytes
2119 );
2120 }
2121 } else {
2122 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2123 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2124
2125 //
2126 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2127 //
2128 VgaReadBitPlanes (
2129 PciIo,
2130 MemAddress + SourceOffset,
2131 VgaFrameBuffer + SourceOffset,
2132 SourceWidth,
2133 Height
2134 );
2135 }
2136
2137 break;
2138
2139 case EfiUgaVideoFill:
2140 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2141 Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2142 LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
2143 RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2144 if (Bytes == 0) {
2145 LeftMask &= RightMask;
2146 RightMask = 0;
2147 }
2148
2149 if (LeftMask == 0xff) {
2150 StartAddress--;
2151 Bytes++;
2152 LeftMask = 0;
2153 }
2154
2155 if (RightMask == 0xff) {
2156 Bytes++;
2157 RightMask = 0;
2158 }
2159
2160 PixelColor = VgaConvertColor (BltBuffer);
2161
2162 //
2163 // Program the Mode Register Write mode 2, Read mode 0
2164 //
2165 WriteGraphicsController (
2166 BiosVideoPrivate->PciIo,
2167 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2168 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2169 );
2170
2171 //
2172 // Program the Data Rotate/Function Select Register to replace
2173 //
2174 WriteGraphicsController (
2175 BiosVideoPrivate->PciIo,
2176 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2177 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2178 );
2179
2180 if (LeftMask != 0) {
2181 //
2182 // Program the BitMask register with the Left column mask
2183 //
2184 WriteGraphicsController (
2185 BiosVideoPrivate->PciIo,
2186 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2187 LeftMask
2188 );
2189
2190 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2191 //
2192 // Read data from the bit planes into the latches
2193 //
2194 PciIo->Mem.Read (
2195 PciIo,
2196 EfiPciIoWidthUint8,
2197 EFI_PCI_IO_PASS_THROUGH_BAR,
2198 (UINT64) Address,
2199 1,
2200 &Data
2201 );
2202 //
2203 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2204 //
2205 PciIo->Mem.Write (
2206 PciIo,
2207 EfiPciIoWidthUint8,
2208 EFI_PCI_IO_PASS_THROUGH_BAR,
2209 (UINT64) Address,
2210 1,
2211 &PixelColor
2212 );
2213 }
2214 }
2215
2216 if (Bytes > 1) {
2217 //
2218 // Program the BitMask register with the middle column mask of 0xff
2219 //
2220 WriteGraphicsController (
2221 BiosVideoPrivate->PciIo,
2222 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2223 0xff
2224 );
2225
2226 for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
2227 PciIo->Mem.Write (
2228 PciIo,
2229 EfiPciIoWidthFillUint8,
2230 EFI_PCI_IO_PASS_THROUGH_BAR,
2231 (UINT64) Address,
2232 Bytes - 1,
2233 &PixelColor
2234 );
2235 }
2236 }
2237
2238 if (RightMask != 0) {
2239 //
2240 // Program the BitMask register with the Right column mask
2241 //
2242 WriteGraphicsController (
2243 BiosVideoPrivate->PciIo,
2244 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2245 RightMask
2246 );
2247
2248 for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
2249 //
2250 // Read data from the bit planes into the latches
2251 //
2252 PciIo->Mem.Read (
2253 PciIo,
2254 EfiPciIoWidthUint8,
2255 EFI_PCI_IO_PASS_THROUGH_BAR,
2256 (UINT64) Address,
2257 1,
2258 &Data
2259 );
2260 //
2261 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2262 //
2263 PciIo->Mem.Write (
2264 PciIo,
2265 EfiPciIoWidthUint8,
2266 EFI_PCI_IO_PASS_THROUGH_BAR,
2267 (UINT64) Address,
2268 1,
2269 &PixelColor
2270 );
2271 }
2272 }
2273 break;
2274
2275 case EfiUgaBltBufferToVideo:
2276 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2277 LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
2278
2279 //
2280 // Program the Mode Register Write mode 2, Read mode 0
2281 //
2282 WriteGraphicsController (
2283 BiosVideoPrivate->PciIo,
2284 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2285 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2286 );
2287
2288 //
2289 // Program the Data Rotate/Function Select Register to replace
2290 //
2291 WriteGraphicsController (
2292 BiosVideoPrivate->PciIo,
2293 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2294 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2295 );
2296
2297 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2298 for (Index1 = 0; Index1 < Width; Index1++) {
2299 BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
2300 }
2301 AddressFix = Address;
2302
2303 for (Bit = 0; Bit < 8; Bit++) {
2304 //
2305 // Program the BitMask register with the Left column mask
2306 //
2307 WriteGraphicsController (
2308 BiosVideoPrivate->PciIo,
2309 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2310 LeftMask
2311 );
2312
2313 for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
2314 //
2315 // Read data from the bit planes into the latches
2316 //
2317 PciIo->Mem.Read (
2318 PciIo,
2319 EfiPciIoWidthUint8,
2320 EFI_PCI_IO_PASS_THROUGH_BAR,
2321 (UINT64) (UINTN) Address1,
2322 1,
2323 &Data
2324 );
2325
2326 PciIo->Mem.Write (
2327 PciIo,
2328 EfiPciIoWidthUint8,
2329 EFI_PCI_IO_PASS_THROUGH_BAR,
2330 (UINT64) (UINTN) Address1,
2331 1,
2332 &BiosVideoPrivate->LineBuffer[Index1]
2333 );
2334 }
2335
2336 LeftMask = (UINT8) (LeftMask >> 1);
2337 if (LeftMask == 0) {
2338 LeftMask = 0x80;
2339 AddressFix++;
2340 }
2341 }
2342 }
2343
2344 break;
2345 default:
2346 break;
2347 }
2348
2349 gBS->RestoreTPL (OriginalTPL);
2350
2351 return EFI_SUCCESS;
2352 }
2353 //
2354 // VGA Mini Port Protocol Functions
2355 //
2356 EFI_STATUS
2357 EFIAPI
2358 BiosVideoVgaMiniPortSetMode (
2359 IN EFI_VGA_MINI_PORT_PROTOCOL *This,
2360 IN UINTN ModeNumber
2361 )
2362 /*++
2363
2364 Routine Description:
2365
2366 VgaMiniPort protocol interface to set mode
2367
2368 Arguments:
2369
2370 This - Pointer to VgaMiniPort protocol instance
2371 ModeNumber - The index of the mode
2372
2373 Returns:
2374
2375 EFI_UNSUPPORTED - The requested mode is not supported
2376 EFI_SUCCESS - The requested mode is set successfully
2377
2378 --*/
2379 {
2380 BIOS_VIDEO_DEV *BiosVideoPrivate;
2381 EFI_IA32_REGISTER_SET Regs;
2382
2383 //
2384 // Make sure the ModeNumber is a valid value
2385 //
2386 if (ModeNumber >= This->MaxMode) {
2387 return EFI_UNSUPPORTED;
2388 }
2389 //
2390 // Get the device structure for this device
2391 //
2392 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
2393
2394 gBS->SetMem (&Regs, sizeof (Regs), 0);
2395
2396 switch (ModeNumber) {
2397 case 0:
2398 //
2399 // Set the 80x25 Text VGA Mode
2400 //
2401 Regs.H.AH = 0x00;
2402 Regs.H.AL = 0x83;
2403 LegacyBiosInt86 (0x10, &Regs);
2404
2405 Regs.H.AH = 0x11;
2406 Regs.H.AL = 0x14;
2407 Regs.H.BL = 0;
2408 LegacyBiosInt86 (0x10, &Regs);
2409 break;
2410
2411 case 1:
2412 //
2413 // Set the 80x50 Text VGA Mode
2414 //
2415 Regs.H.AH = 0x00;
2416 Regs.H.AL = 0x83;
2417 LegacyBiosInt86 (0x10, &Regs);
2418 Regs.H.AH = 0x11;
2419 Regs.H.AL = 0x12;
2420 Regs.H.BL = 0;
2421 LegacyBiosInt86 (0x10, &Regs);
2422 break;
2423
2424 default:
2425 return EFI_UNSUPPORTED;
2426 }
2427
2428 return EFI_SUCCESS;
2429 }
2430
2431 VOID
2432 InitializeBiosIntCaller (
2433 VOID
2434 )
2435 {
2436 EFI_STATUS Status;
2437 UINT32 RealModeBufferSize;
2438 UINT32 ExtraStackSize;
2439 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
2440
2441 //
2442 // Get LegacyRegion
2443 //
2444 AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);
2445
2446 LegacyRegionBase = 0x100000;
2447 Status = gBS->AllocatePages (
2448 AllocateMaxAddress,
2449 EfiACPIMemoryNVS,
2450 EFI_SIZE_TO_PAGES(RealModeBufferSize + ExtraStackSize + 200),
2451 &LegacyRegionBase
2452 );
2453 ASSERT_EFI_ERROR (Status);
2454
2455 mThunkContext.RealModeBuffer = (VOID*)(UINTN)LegacyRegionBase;
2456 mThunkContext.RealModeBufferSize = EFI_PAGES_TO_SIZE (RealModeBufferSize);
2457 mThunkContext.ThunkAttributes = 3;
2458 AsmPrepareThunk16(&mThunkContext);
2459
2460 //Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
2461 //ASSERT_EFI_ERROR (Status);
2462 }
2463
2464 VOID
2465 InitializeInterruptRedirection (
2466 VOID
2467 )
2468 /*++
2469
2470 Routine Description:
2471 Initialize interrupt redirection code and entries, because
2472 IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
2473 Or the interrupt will lost when we do thunk.
2474 NOTE: We do not reset 8259 vector base, because it will cause pending
2475 interrupt lost.
2476
2477 Arguments:
2478 NONE
2479
2480 Returns:
2481 NONE
2482 --*/
2483 {
2484 EFI_STATUS Status;
2485 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
2486 UINTN LegacyRegionLength;
2487 UINT32 *IdtArray;
2488 UINTN Index;
2489 UINT8 ProtectedModeBaseVector;
2490 UINT32 InterruptRedirectionCode[] = {
2491 0x90CF08CD, // INT8; IRET; NOP
2492 0x90CF09CD, // INT9; IRET; NOP
2493 0x90CF0ACD, // INTA; IRET; NOP
2494 0x90CF0BCD, // INTB; IRET; NOP
2495 0x90CF0CCD, // INTC; IRET; NOP
2496 0x90CF0DCD, // INTD; IRET; NOP
2497 0x90CF0ECD, // INTE; IRET; NOP
2498 0x90CF0FCD // INTF; IRET; NOP
2499 };
2500
2501 //
2502 // Get LegacyRegion
2503 //
2504 LegacyRegionLength = sizeof(InterruptRedirectionCode);
2505 LegacyRegionBase = 0x100000;
2506 Status = gBS->AllocatePages (
2507 AllocateMaxAddress,
2508 EfiACPIMemoryNVS,
2509 EFI_SIZE_TO_PAGES(LegacyRegionLength),
2510 &LegacyRegionBase
2511 );
2512 ASSERT_EFI_ERROR (Status);
2513
2514 //
2515 // Copy code to legacy region
2516 //
2517 CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));
2518
2519 //
2520 // Get VectorBase, it should be 0x68
2521 //
2522 Status = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, &ProtectedModeBaseVector);
2523 ASSERT_EFI_ERROR (Status);
2524
2525 //
2526 // Patch IVT 0x68 ~ 0x6f
2527 //
2528 IdtArray = (UINT32 *) 0;
2529 for (Index = 0; Index < 8; Index++) {
2530 IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));
2531 }
2532
2533 return ;
2534 }
2535
2536 BOOLEAN
2537 EFIAPI
2538 LegacyBiosInt86 (
2539 IN UINT8 BiosInt,
2540 IN EFI_IA32_REGISTER_SET *Regs
2541 )
2542 /*++
2543
2544 Routine Description:
2545 Thunk to 16-bit real mode and execute a software interrupt with a vector
2546 of BiosInt. Regs will contain the 16-bit register context on entry and
2547 exit.
2548
2549 Arguments:
2550 This - Protocol instance pointer.
2551 BiosInt - Processor interrupt vector to invoke
2552 Reg - Register contexted passed into (and returned) from thunk to
2553 16-bit mode
2554
2555 Returns:
2556 FALSE - Thunk completed, and there were no BIOS errors in the target code.
2557 See Regs for status.
2558 TRUE - There was a BIOS erro in the target code.
2559
2560 --*/
2561 {
2562 UINTN Status;
2563 UINT32 Eflags;
2564 IA32_REGISTER_SET ThunkRegSet;
2565 BOOLEAN Ret;
2566 UINT16 *Stack16;
2567
2568 Regs->X.Flags.Reserved1 = 1;
2569 Regs->X.Flags.Reserved2 = 0;
2570 Regs->X.Flags.Reserved3 = 0;
2571 Regs->X.Flags.Reserved4 = 0;
2572 Regs->X.Flags.IOPL = 3;
2573 Regs->X.Flags.NT = 0;
2574 Regs->X.Flags.IF = 1;
2575 Regs->X.Flags.TF = 0;
2576 Regs->X.Flags.CF = 0;
2577
2578 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
2579 ThunkRegSet.E.EDI = Regs->E.EDI;
2580 ThunkRegSet.E.ESI = Regs->E.ESI;
2581 ThunkRegSet.E.EBP = Regs->E.EBP;
2582 ThunkRegSet.E.EBX = Regs->E.EBX;
2583 ThunkRegSet.E.EDX = Regs->E.EDX;
2584 ThunkRegSet.E.ECX = Regs->E.ECX;
2585 ThunkRegSet.E.EAX = Regs->E.EAX;
2586 ThunkRegSet.E.DS = Regs->E.DS;
2587 ThunkRegSet.E.ES = Regs->E.ES;
2588
2589 CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32));
2590
2591 //
2592 // The call to Legacy16 is a critical section to EFI
2593 //
2594 Eflags = AsmReadEflags ();
2595 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
2596 DisableInterrupts ();
2597 }
2598
2599 //
2600 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
2601 //
2602 Status = mLegacy8259->SetMode (mLegacy8259, Efi8259LegacyMode, NULL, NULL);
2603 ASSERT_EFI_ERROR (Status);
2604
2605 Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
2606 Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16);
2607 CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS));
2608
2609 ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
2610 ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
2611 ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];
2612 ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);
2613 mThunkContext.RealModeState = &ThunkRegSet;
2614 AsmThunk16 (&mThunkContext);
2615
2616 //
2617 // Restore protected mode interrupt state
2618 //
2619 Status = mLegacy8259->SetMode (mLegacy8259, Efi8259ProtectedMode, NULL, NULL);
2620 ASSERT_EFI_ERROR (Status);
2621
2622 //
2623 // End critical section
2624 //
2625 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
2626 EnableInterrupts ();
2627 }
2628
2629 Regs->E.EDI = ThunkRegSet.E.EDI;
2630 Regs->E.ESI = ThunkRegSet.E.ESI;
2631 Regs->E.EBP = ThunkRegSet.E.EBP;
2632 Regs->E.EBX = ThunkRegSet.E.EBX;
2633 Regs->E.EDX = ThunkRegSet.E.EDX;
2634 Regs->E.ECX = ThunkRegSet.E.ECX;
2635 Regs->E.EAX = ThunkRegSet.E.EAX;
2636 Regs->E.SS = ThunkRegSet.E.SS;
2637 Regs->E.CS = ThunkRegSet.E.CS;
2638 Regs->E.DS = ThunkRegSet.E.DS;
2639 Regs->E.ES = ThunkRegSet.E.ES;
2640
2641 CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
2642
2643 Ret = (BOOLEAN) (Regs->E.EFlags.CF == 1);
2644
2645 return Ret;
2646 }
2647
2648