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