]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/BiosVideoThunkDxe/BiosVideo.c
Final boot image just need combination, no need to create directory
[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 // INT 10 - VESA SuperVGA BIOS (VBE) - GET SuperVGA INFORMATION
1092 //
1093 // AX = 4F00h
1094 // ES:DI -> buffer for SuperVGA information (see #00077)
1095 // Return: AL = 4Fh if function supported
1096 // AH = status
1097 // 00h successful
1098 // ES:DI buffer filled
1099 // 01h failed
1100 // ---VBE v2.0---
1101 // 02h function not supported by current hardware configuration
1102 // 03h function invalid in current video mode
1103 // Desc: determine whether VESA BIOS extensions are present and the capabilities
1104 // supported by the display adapter
1105 //
1106 gBS->SetMem (&Regs, sizeof (Regs), 0);
1107 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
1108 gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
1109 BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
1110 Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1111 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
1112
1113 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
1114
1115 Status = EFI_DEVICE_ERROR;
1116
1117 //
1118 // See if the VESA call succeeded
1119 //
1120 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1121 return Status;
1122 }
1123 //
1124 // Check for 'VESA' signature
1125 //
1126 if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
1127 return Status;
1128 }
1129 //
1130 // Check to see if this is VBE 2.0 or higher
1131 //
1132 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
1133 return Status;
1134 }
1135
1136 //
1137 // Read EDID information
1138 //
1139 // INT 10 - VESA VBE/DC (Display Data Channel) - READ EDID
1140 //
1141 // AX = 4F15h
1142 // BL = 01h
1143 // CX = 0000h
1144 // DX = 0000h
1145 // ES:DI -> 128-byte buffer for EDID record (see #00127)
1146 // Return: AL = 4Fh if function supported
1147 // AH = status
1148 // 00h successful
1149 // ES:DI buffer filled
1150 // 01h failed (e.g. non-DDC monitor)
1151 //
1152 gBS->SetMem (&Regs, sizeof (Regs), 0);
1153 Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
1154 Regs.X.BX = 1;
1155 Regs.X.CX = 0;
1156 Regs.X.DX = 0;
1157 Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1158 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
1159
1160 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
1161
1162 //
1163 // See if the VESA call succeeded
1164 //
1165 EdidFound = FALSE;
1166 if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1167 //
1168 // Parse EDID data structure to retrieve modes supported by monitor
1169 //
1170 if (ParseEdidData ((UINT8 *) BiosVideoPrivate->VbeEdidDataBlock, &ValidEdidTiming) == TRUE) {
1171 EdidFound = TRUE;
1172
1173 BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1174 Status = gBS->AllocatePool (
1175 EfiBootServicesData,
1176 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1177 (VOID**) &BiosVideoPrivate->EdidDiscovered.Edid
1178 );
1179 if (EFI_ERROR (Status)) {
1180 goto Done;
1181 }
1182 gBS->CopyMem (
1183 BiosVideoPrivate->EdidDiscovered.Edid,
1184 BiosVideoPrivate->VbeEdidDataBlock,
1185 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
1186 );
1187
1188 BiosVideoPrivate->EdidActive.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
1189 Status = gBS->AllocatePool (
1190 EfiBootServicesData,
1191 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
1192 (VOID**)&BiosVideoPrivate->EdidActive.Edid
1193 );
1194 if (EFI_ERROR (Status)) {
1195 goto Done;
1196 }
1197 gBS->CopyMem (
1198 BiosVideoPrivate->EdidActive.Edid,
1199 BiosVideoPrivate->VbeEdidDataBlock,
1200 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
1201 );
1202 } else {
1203 BiosVideoPrivate->EdidDiscovered.SizeOfEdid = 0;
1204 BiosVideoPrivate->EdidDiscovered.Edid = NULL;
1205
1206 BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
1207 BiosVideoPrivate->EdidActive.Edid = NULL;
1208 }
1209 }
1210
1211 //
1212 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1213 //
1214 ModeNumberPtr = (UINT16 *)
1215 (
1216 (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
1217 ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
1218 );
1219
1220 PreferMode = 0;
1221 ModeNumber = 0;
1222
1223 for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {
1224 //
1225 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1226 //
1227 if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
1228 continue;
1229 }
1230 //
1231 // Get the information about the mode
1232 //
1233 // INT 10 - VESA SuperVGA BIOS - GET SuperVGA MODE INFORMATION
1234 //
1235 // AX = 4F01h
1236 // CX = SuperVGA video mode (see #04082 for bitfields)
1237 // ES:DI -> 256-byte buffer for mode information (see #00079)
1238 // Return: AL = 4Fh if function supported
1239 // AH = status
1240 // 00h successful
1241 // ES:DI buffer filled
1242 // 01h failed
1243 // Desc: determine the attributes of the specified video mode
1244 //
1245 gBS->SetMem (&Regs, sizeof (Regs), 0);
1246 Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
1247 Regs.X.CX = *ModeNumberPtr;
1248 gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
1249 Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1250 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
1251
1252 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
1253
1254 //
1255 // See if the call succeeded. If it didn't, then try the next mode.
1256 //
1257 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1258 continue;
1259 }
1260 //
1261 // See if the mode supports color. If it doesn't then try the next mode.
1262 //
1263 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
1264 continue;
1265 }
1266 //
1267 // See if the mode supports graphics. If it doesn't then try the next mode.
1268 //
1269 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
1270 continue;
1271 }
1272 //
1273 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1274 //
1275 if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
1276 continue;
1277 }
1278 //
1279 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1280 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1281 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1282 //
1283 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
1284 continue;
1285 }
1286
1287 if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
1288 continue;
1289 }
1290
1291 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
1292 continue;
1293 }
1294 //
1295 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1296 //
1297 if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
1298 continue;
1299 }
1300
1301 if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
1302 //
1303 // EDID exist, check whether this mode match with any mode in EDID
1304 //
1305 Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1306 Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1307 if (SearchEdidTiming (&ValidEdidTiming, &Timing) == FALSE) {
1308 continue;
1309 }
1310 }
1311
1312 //
1313 // Select a reasonable mode to be set for current display mode
1314 //
1315 ModeFound = FALSE;
1316
1317 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
1318 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
1319 ) {
1320 ModeFound = TRUE;
1321 }
1322 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
1323 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
1324 ) {
1325 ModeFound = TRUE;
1326 PreferMode = ModeNumber;
1327 }
1328 if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
1329 BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
1330 ) {
1331 ModeFound = TRUE;
1332 }
1333 if ((!EdidFound) && (!ModeFound)) {
1334 //
1335 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1336 //
1337 continue;
1338 }
1339
1340 //
1341 // Add mode to the list of available modes
1342 //
1343 ModeNumber ++;
1344 Status = gBS->AllocatePool (
1345 EfiBootServicesData,
1346 ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA),
1347 (VOID **) &ModeBuffer
1348 );
1349 if (EFI_ERROR (Status)) {
1350 goto Done;
1351 }
1352
1353 if (ModeNumber > 1) {
1354 gBS->CopyMem (
1355 ModeBuffer,
1356 BiosVideoPrivate->ModeData,
1357 (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
1358 );
1359 }
1360
1361 if (BiosVideoPrivate->ModeData != NULL) {
1362 gBS->FreePool (BiosVideoPrivate->ModeData);
1363 }
1364
1365 CurrentModeData = &ModeBuffer[ModeNumber - 1];
1366 CurrentModeData->VbeModeNumber = *ModeNumberPtr;
1367 if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
1368 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
1369 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
1370 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
1371 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
1372 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
1373 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
1374 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
1375 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
1376 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
1377 } else {
1378 CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
1379 CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
1380 CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
1381 CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
1382 CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
1383 CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
1384 CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
1385 CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
1386 CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
1387 }
1388 CurrentModeData->PixelFormat = PixelBitMask;
1389 if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
1390 (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
1391 if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
1392 CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
1393 } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
1394 CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
1395 }
1396 }
1397 CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
1398 CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
1399 CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
1400 CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
1401
1402 CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
1403 CurrentModeData->FrameBufferSize = BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024;
1404 CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
1405 CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
1406
1407 CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
1408
1409 BiosVideoPrivate->ModeData = ModeBuffer;
1410 }
1411 //
1412 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1413 //
1414 if (ModeNumber == 0) {
1415 Status = EFI_DEVICE_ERROR;
1416 goto Done;
1417 }
1418
1419 //
1420 // Allocate buffer for Graphics Output Protocol mode information
1421 //
1422 Status = gBS->AllocatePool (
1423 EfiBootServicesData,
1424 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
1425 (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode
1426 );
1427 if (EFI_ERROR (Status)) {
1428 goto Done;
1429 }
1430 GraphicsOutputMode = BiosVideoPrivate->GraphicsOutput.Mode;
1431 Status = gBS->AllocatePool (
1432 EfiBootServicesData,
1433 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
1434 (VOID **) &GraphicsOutputMode->Info
1435 );
1436 if (EFI_ERROR (Status)) {
1437 goto Done;
1438 }
1439
1440 GraphicsOutputMode->MaxMode = (UINT32) ModeNumber;
1441 //
1442 // Current mode is unknow till now, set it to an invalid mode.
1443 //
1444 GraphicsOutputMode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1445
1446 //
1447 // Find the best mode to initialize
1448 //
1449 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
1450 if (EFI_ERROR (Status)) {
1451 for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
1452 Status = BiosVideoGraphicsOutputSetMode (
1453 &BiosVideoPrivate->GraphicsOutput,
1454 (UINT32) PreferMode
1455 );
1456 if (!EFI_ERROR (Status)) {
1457 break;
1458 }
1459 }
1460 if (PreferMode == ModeNumber) {
1461 //
1462 // None mode is set successfully.
1463 //
1464 goto Done;
1465 }
1466 }
1467
1468 Done:
1469 //
1470 // If there was an error, then free the mode structure
1471 //
1472 if (EFI_ERROR (Status)) {
1473 if (BiosVideoPrivate->ModeData != NULL) {
1474 gBS->FreePool (BiosVideoPrivate->ModeData);
1475 }
1476 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1477 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1478 gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1479 }
1480 gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1481 }
1482 }
1483
1484 return Status;
1485 }
1486
1487 /**
1488 Check for VGA device
1489
1490 @param BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
1491
1492 @retval EFI_SUCCESS Standard VGA device found
1493 **/
1494 EFI_STATUS
1495 EFIAPI
1496 BiosVideoCheckForVga (
1497 IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
1498 )
1499 {
1500 EFI_STATUS Status;
1501 BIOS_VIDEO_MODE_DATA *ModeBuffer;
1502
1503 //
1504 // Fill in the Graphics Output Protocol
1505 //
1506 BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
1507 BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode;
1508 BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt;
1509
1510 //
1511 // Allocate buffer for Graphics Output Protocol mode information
1512 //
1513 Status = gBS->AllocatePool (
1514 EfiBootServicesData,
1515 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE),
1516 (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode
1517 );
1518 if (EFI_ERROR (Status)) {
1519 goto Done;
1520 }
1521 Status = gBS->AllocatePool (
1522 EfiBootServicesData,
1523 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
1524 (VOID **) &BiosVideoPrivate->GraphicsOutput.Mode->Info
1525 );
1526 if (EFI_ERROR (Status)) {
1527 goto Done;
1528 }
1529
1530 //
1531 // Add mode to the list of available modes
1532 //
1533 BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
1534
1535 Status = gBS->AllocatePool (
1536 EfiBootServicesData,
1537 sizeof (BIOS_VIDEO_MODE_DATA),
1538 (VOID **) &ModeBuffer
1539 );
1540 if (EFI_ERROR (Status)) {
1541 goto Done;
1542 }
1543
1544 ModeBuffer->VbeModeNumber = 0x0012;
1545 ModeBuffer->BytesPerScanLine = 640;
1546 ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000);
1547 ModeBuffer->FrameBufferSize = 0;
1548 ModeBuffer->HorizontalResolution = 640;
1549 ModeBuffer->VerticalResolution = 480;
1550 ModeBuffer->BitsPerPixel = 8;
1551 ModeBuffer->PixelFormat = PixelBltOnly;
1552
1553 BiosVideoPrivate->ModeData = ModeBuffer;
1554
1555 //
1556 // Test to see if the Video Adapter support the 640x480 16 color mode
1557 //
1558 BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
1559 Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
1560
1561 Done:
1562 //
1563 // If there was an error, then free the mode structure
1564 //
1565 if (EFI_ERROR (Status)) {
1566 if (BiosVideoPrivate->ModeData != NULL) {
1567 gBS->FreePool (BiosVideoPrivate->ModeData);
1568 }
1569 if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
1570 if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
1571 gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
1572 }
1573 gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
1574 }
1575 }
1576 return Status;
1577 }
1578 //
1579 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1580 //
1581 /**
1582
1583 Graphics Output protocol interface to get video mode
1584
1585
1586 @param This - Protocol instance pointer.
1587 @param ModeNumber - The mode number to return information on.
1588 @param SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
1589 @param Info - Caller allocated buffer that returns information about ModeNumber.
1590
1591 @return EFI_SUCCESS - Mode information returned.
1592 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
1593 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
1594 EFI_INVALID_PARAMETER - One of the input args was NULL.
1595
1596 **/
1597 EFI_STATUS
1598 EFIAPI
1599 BiosVideoGraphicsOutputQueryMode (
1600 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
1601 IN UINT32 ModeNumber,
1602 OUT UINTN *SizeOfInfo,
1603 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
1604 )
1605 {
1606 BIOS_VIDEO_DEV *BiosVideoPrivate;
1607 EFI_STATUS Status;
1608 BIOS_VIDEO_MODE_DATA *ModeData;
1609
1610 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1611
1612 if (BiosVideoPrivate->HardwareNeedsStarting) {
1613 return EFI_NOT_STARTED;
1614 }
1615
1616 if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
1617 return EFI_INVALID_PARAMETER;
1618 }
1619
1620 Status = gBS->AllocatePool (
1621 EfiBootServicesData,
1622 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION),
1623 (VOID**) Info
1624 );
1625 if (EFI_ERROR (Status)) {
1626 return Status;
1627 }
1628
1629 *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1630
1631 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1632 (*Info)->Version = 0;
1633 (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
1634 (*Info)->VerticalResolution = ModeData->VerticalResolution;
1635 (*Info)->PixelFormat = ModeData->PixelFormat;
1636 (*Info)->PixelInformation = ModeData->PixelBitMask;
1637
1638 (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1639
1640 return EFI_SUCCESS;
1641 }
1642
1643 /**
1644
1645 Graphics Output protocol interface to set video mode
1646
1647
1648 @param This - Protocol instance pointer.
1649 @param ModeNumber - The mode number to be set.
1650
1651 @return EFI_SUCCESS - Graphics mode was changed.
1652 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
1653 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
1654
1655 **/
1656 EFI_STATUS
1657 EFIAPI
1658 BiosVideoGraphicsOutputSetMode (
1659 IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
1660 IN UINT32 ModeNumber
1661 )
1662 {
1663 EFI_STATUS Status;
1664 BIOS_VIDEO_DEV *BiosVideoPrivate;
1665 IA32_REGISTER_SET Regs;
1666 BIOS_VIDEO_MODE_DATA *ModeData;
1667
1668 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1669
1670 if (This == NULL) {
1671 return EFI_INVALID_PARAMETER;
1672 }
1673
1674 if (ModeNumber >= This->Mode->MaxMode) {
1675 return EFI_UNSUPPORTED;
1676 }
1677
1678 if (ModeNumber == This->Mode->Mode) {
1679 return EFI_SUCCESS;
1680 }
1681
1682 ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
1683
1684 if (BiosVideoPrivate->LineBuffer) {
1685 gBS->FreePool (BiosVideoPrivate->LineBuffer);
1686 }
1687
1688 if (BiosVideoPrivate->VgaFrameBuffer) {
1689 gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer);
1690 }
1691
1692 if (BiosVideoPrivate->VbeFrameBuffer) {
1693 gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer);
1694 }
1695
1696 BiosVideoPrivate->LineBuffer = NULL;
1697 Status = gBS->AllocatePool (
1698 EfiBootServicesData,
1699 ModeData->BytesPerScanLine,
1700 (VOID**) &BiosVideoPrivate->LineBuffer
1701 );
1702 if (EFI_ERROR (Status)) {
1703 return Status;
1704 }
1705 //
1706 // Clear all registers
1707 //
1708 gBS->SetMem (&Regs, sizeof (Regs), 0);
1709
1710 if (ModeData->VbeModeNumber < 0x100) {
1711 //
1712 // Allocate a working buffer for BLT operations to the VGA frame buffer
1713 //
1714 BiosVideoPrivate->VgaFrameBuffer = NULL;
1715 Status = gBS->AllocatePool (
1716 EfiBootServicesData,
1717 4 * 480 * 80,
1718 (VOID**) &BiosVideoPrivate->VgaFrameBuffer
1719 );
1720 if (EFI_ERROR (Status)) {
1721 return Status;
1722 }
1723 //
1724 // Set VGA Mode
1725 //
1726 Regs.X.AX = ModeData->VbeModeNumber;
1727 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
1728
1729 } else {
1730 //
1731 // Allocate a working buffer for BLT operations to the VBE frame buffer
1732 //
1733 BiosVideoPrivate->VbeFrameBuffer = NULL;
1734 Status = gBS->AllocatePool (
1735 EfiBootServicesData,
1736 ModeData->BytesPerScanLine * ModeData->VerticalResolution,
1737 (VOID**) &BiosVideoPrivate->VbeFrameBuffer
1738 );
1739 if (EFI_ERROR (Status)) {
1740 return Status;
1741 }
1742 //
1743 // Set VBE mode
1744 //
1745 Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
1746 Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
1747 gBS->SetMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK), 0);
1748 Regs.E.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
1749 Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
1750
1751 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
1752
1753 //
1754 // Check to see if the call succeeded
1755 //
1756 if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
1757 return EFI_DEVICE_ERROR;
1758 }
1759 //
1760 // Initialize the state of the VbeFrameBuffer
1761 //
1762 Status = BiosVideoPrivate->PciIo->Mem.Read (
1763 BiosVideoPrivate->PciIo,
1764 EfiPciIoWidthUint32,
1765 EFI_PCI_IO_PASS_THROUGH_BAR,
1766 (UINT64) (UINTN) ModeData->LinearFrameBuffer,
1767 (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
1768 BiosVideoPrivate->VbeFrameBuffer
1769 );
1770 if (EFI_ERROR (Status)) {
1771 return Status;
1772 }
1773 }
1774
1775 This->Mode->Mode = ModeNumber;
1776 This->Mode->Info->Version = 0;
1777 This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
1778 This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
1779 This->Mode->Info->PixelFormat = ModeData->PixelFormat;
1780 This->Mode->Info->PixelInformation = ModeData->PixelBitMask;
1781 This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
1782 This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
1783
1784 //
1785 // Frame BufferSize remain unchanged
1786 //
1787 This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ModeData->LinearFrameBuffer;
1788 This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
1789
1790 BiosVideoPrivate->HardwareNeedsStarting = FALSE;
1791
1792 return EFI_SUCCESS;
1793 }
1794
1795 /**
1796
1797 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
1798
1799
1800 @param PciIo - The pointer of EFI_PCI_IO_PROTOCOL
1801 @param VbeBuffer - The data to transfer to screen
1802 @param MemAddress - Physical frame buffer base address
1803 @param DestinationX - The X coordinate of the destination for BltOperation
1804 @param DestinationY - The Y coordinate of the destination for BltOperation
1805 @param TotalBytes - The total bytes of copy
1806 @param VbePixelWidth - Bytes per pixel
1807 @param BytesPerScanLine - Bytes per scan line
1808
1809 @return None.
1810
1811 **/
1812 VOID
1813 CopyVideoBuffer (
1814 IN EFI_PCI_IO_PROTOCOL *PciIo,
1815 IN UINT8 *VbeBuffer,
1816 IN VOID *MemAddress,
1817 IN UINTN DestinationX,
1818 IN UINTN DestinationY,
1819 IN UINTN TotalBytes,
1820 IN UINT32 VbePixelWidth,
1821 IN UINTN BytesPerScanLine
1822 )
1823 {
1824 UINTN FrameBufferAddr;
1825 UINTN CopyBlockNum;
1826 UINTN RemainingBytes;
1827 UINTN UnalignedBytes;
1828 EFI_STATUS Status;
1829
1830 FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
1831
1832 //
1833 // If TotalBytes is less than 4 bytes, only start byte copy.
1834 //
1835 if (TotalBytes < 4) {
1836 Status = PciIo->Mem.Write (
1837 PciIo,
1838 EfiPciIoWidthUint8,
1839 EFI_PCI_IO_PASS_THROUGH_BAR,
1840 (UINT64) FrameBufferAddr,
1841 TotalBytes,
1842 VbeBuffer
1843 );
1844 ASSERT_EFI_ERROR (Status);
1845 return;
1846 }
1847
1848 //
1849 // If VbeBuffer is not 4-byte aligned, start byte copy.
1850 //
1851 UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
1852
1853 if (UnalignedBytes != 0) {
1854 Status = PciIo->Mem.Write (
1855 PciIo,
1856 EfiPciIoWidthUint8,
1857 EFI_PCI_IO_PASS_THROUGH_BAR,
1858 (UINT64) FrameBufferAddr,
1859 UnalignedBytes,
1860 VbeBuffer
1861 );
1862 ASSERT_EFI_ERROR (Status);
1863 FrameBufferAddr += UnalignedBytes;
1864 VbeBuffer += UnalignedBytes;
1865 }
1866
1867 //
1868 // Calculate 4-byte block count and remaining bytes.
1869 //
1870 CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
1871 RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
1872
1873 //
1874 // Copy 4-byte block and remaining bytes to physical frame buffer.
1875 //
1876 if (CopyBlockNum != 0) {
1877 Status = PciIo->Mem.Write (
1878 PciIo,
1879 EfiPciIoWidthUint32,
1880 EFI_PCI_IO_PASS_THROUGH_BAR,
1881 (UINT64) FrameBufferAddr,
1882 CopyBlockNum,
1883 VbeBuffer
1884 );
1885 ASSERT_EFI_ERROR (Status);
1886 }
1887
1888 if (RemainingBytes != 0) {
1889 FrameBufferAddr += (CopyBlockNum << 2);
1890 VbeBuffer += (CopyBlockNum << 2);
1891 Status = PciIo->Mem.Write (
1892 PciIo,
1893 EfiPciIoWidthUint8,
1894 EFI_PCI_IO_PASS_THROUGH_BAR,
1895 (UINT64) FrameBufferAddr,
1896 RemainingBytes,
1897 VbeBuffer
1898 );
1899 ASSERT_EFI_ERROR (Status);
1900 }
1901 }
1902
1903 //
1904 // BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes
1905 //
1906 /**
1907
1908 Graphics Output protocol instance to block transfer for VBE device
1909
1910
1911 @param This - Pointer to Graphics Output protocol instance
1912 @param BltBuffer - The data to transfer to screen
1913 @param BltOperation - The operation to perform
1914 @param SourceX - The X coordinate of the source for BltOperation
1915 @param SourceY - The Y coordinate of the source for BltOperation
1916 @param DestinationX - The X coordinate of the destination for BltOperation
1917 @param DestinationY - The Y coordinate of the destination for BltOperation
1918 @param Width - The width of a rectangle in the blt rectangle in pixels
1919 @param Height - The height of a rectangle in the blt rectangle in pixels
1920 @param Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
1921 If a Delta of 0 is used, the entire BltBuffer will be operated on.
1922 If a subrectangle of the BltBuffer is used, then Delta represents
1923 the number of bytes in a row of the BltBuffer.
1924
1925 @return EFI_INVALID_PARAMETER - Invalid parameter passed in
1926 EFI_SUCCESS - Blt operation success
1927
1928 **/
1929 EFI_STATUS
1930 EFIAPI
1931 BiosVideoGraphicsOutputVbeBlt (
1932 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
1933 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
1934 IN EFI_GRAPHICS_OUTPUT_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 BIOS_VIDEO_DEV *BiosVideoPrivate;
1945 BIOS_VIDEO_MODE_DATA *Mode;
1946 EFI_PCI_IO_PROTOCOL *PciIo;
1947 EFI_TPL OriginalTPL;
1948 UINTN DstY;
1949 UINTN SrcY;
1950 UINTN DstX;
1951 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
1952 VOID *MemAddress;
1953 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
1954 UINTN BytesPerScanLine;
1955 UINTN Index;
1956 UINT8 *VbeBuffer;
1957 UINT8 *VbeBuffer1;
1958 UINT8 *BltUint8;
1959 UINT32 VbePixelWidth;
1960 UINT32 Pixel;
1961 UINTN TotalBytes;
1962
1963 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
1964 Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode];
1965 PciIo = BiosVideoPrivate->PciIo;
1966
1967 VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
1968 MemAddress = Mode->LinearFrameBuffer;
1969 BytesPerScanLine = Mode->BytesPerScanLine;
1970 VbePixelWidth = Mode->BitsPerPixel / 8;
1971 BltUint8 = (UINT8 *) BltBuffer;
1972 TotalBytes = Width * VbePixelWidth;
1973
1974 if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
1975 return EFI_INVALID_PARAMETER;
1976 }
1977
1978 if (Width == 0 || Height == 0) {
1979 return EFI_INVALID_PARAMETER;
1980 }
1981 //
1982 // We need to fill the Virtual Screen buffer with the blt data.
1983 // The virtual screen is upside down, as the first row is the bootom row of
1984 // the image.
1985 //
1986 if (BltOperation == EfiBltVideoToBltBuffer) {
1987 //
1988 // Video to BltBuffer: Source is Video, destination is BltBuffer
1989 //
1990 if (SourceY + Height > Mode->VerticalResolution) {
1991 return EFI_INVALID_PARAMETER;
1992 }
1993
1994 if (SourceX + Width > Mode->HorizontalResolution) {
1995 return EFI_INVALID_PARAMETER;
1996 }
1997 } else {
1998 //
1999 // BltBuffer to Video: Source is BltBuffer, destination is Video
2000 //
2001 if (DestinationY + Height > Mode->VerticalResolution) {
2002 return EFI_INVALID_PARAMETER;
2003 }
2004
2005 if (DestinationX + Width > Mode->HorizontalResolution) {
2006 return EFI_INVALID_PARAMETER;
2007 }
2008 }
2009 //
2010 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2011 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2012 // the number of bytes in each row can be computed.
2013 //
2014 if (Delta == 0) {
2015 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2016 }
2017 //
2018 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2019 // We would not want a timer based event (Cursor, ...) to come in while we are
2020 // doing this operation.
2021 //
2022 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2023
2024 switch (BltOperation) {
2025 case EfiBltVideoToBltBuffer:
2026 for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
2027 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2028 //
2029 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2030 //
2031 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
2032 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2033 Pixel = *(UINT32 *) (VbeBuffer);
2034 Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
2035 Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
2036 Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
2037 Blt->Reserved = 0;
2038 Blt++;
2039 VbeBuffer += VbePixelWidth;
2040 }
2041
2042 }
2043 break;
2044
2045 case EfiBltVideoToVideo:
2046 for (Index = 0; Index < Height; Index++) {
2047 if (DestinationY <= SourceY) {
2048 SrcY = SourceY + Index;
2049 DstY = DestinationY + Index;
2050 } else {
2051 SrcY = SourceY + Height - Index - 1;
2052 DstY = DestinationY + Height - Index - 1;
2053 }
2054
2055 VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
2056 VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
2057
2058 gBS->CopyMem (
2059 VbeBuffer,
2060 VbeBuffer1,
2061 TotalBytes
2062 );
2063
2064 //
2065 // Update physical frame buffer.
2066 //
2067 CopyVideoBuffer (
2068 PciIo,
2069 VbeBuffer,
2070 MemAddress,
2071 DestinationX,
2072 DstY,
2073 TotalBytes,
2074 VbePixelWidth,
2075 BytesPerScanLine
2076 );
2077 }
2078 break;
2079
2080 case EfiBltVideoFill:
2081 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2082 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
2083 //
2084 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2085 //
2086 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2087 (
2088 (Blt->Green & Mode->Green.Mask) <<
2089 Mode->Green.Position
2090 ) |
2091 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2092
2093 for (Index = 0; Index < Width; Index++) {
2094 gBS->CopyMem (
2095 VbeBuffer,
2096 &Pixel,
2097 VbePixelWidth
2098 );
2099 VbeBuffer += VbePixelWidth;
2100 }
2101
2102 VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
2103 for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
2104 gBS->CopyMem (
2105 (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
2106 VbeBuffer,
2107 TotalBytes
2108 );
2109 }
2110 for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
2111 //
2112 // Update physical frame buffer.
2113 //
2114 CopyVideoBuffer (
2115 PciIo,
2116 VbeBuffer,
2117 MemAddress,
2118 DestinationX,
2119 DstY,
2120 TotalBytes,
2121 VbePixelWidth,
2122 BytesPerScanLine
2123 );
2124 }
2125 break;
2126
2127 case EfiBltBufferToVideo:
2128 for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
2129 Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
2130 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2131 for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
2132 //
2133 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2134 //
2135 Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
2136 ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
2137 ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
2138 gBS->CopyMem (
2139 VbeBuffer,
2140 &Pixel,
2141 VbePixelWidth
2142 );
2143 Blt++;
2144 VbeBuffer += VbePixelWidth;
2145 }
2146
2147 VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
2148
2149 //
2150 // Update physical frame buffer.
2151 //
2152 CopyVideoBuffer (
2153 PciIo,
2154 VbeBuffer,
2155 MemAddress,
2156 DestinationX,
2157 DstY,
2158 TotalBytes,
2159 VbePixelWidth,
2160 BytesPerScanLine
2161 );
2162 }
2163 break;
2164 default:
2165 break;
2166 }
2167
2168 gBS->RestoreTPL (OriginalTPL);
2169
2170 return EFI_SUCCESS;
2171 }
2172
2173 /**
2174
2175 Write graphics controller registers
2176
2177
2178 @param PciIo - Pointer to PciIo protocol instance of the controller
2179 @param Address - Register address
2180 @param Data - Data to be written to register
2181
2182 @return None
2183
2184 **/
2185 STATIC
2186 VOID
2187 WriteGraphicsController (
2188 IN EFI_PCI_IO_PROTOCOL *PciIo,
2189 IN UINTN Address,
2190 IN UINTN Data
2191 )
2192 {
2193 Address = Address | (Data << 8);
2194 PciIo->Io.Write (
2195 PciIo,
2196 EfiPciIoWidthUint16,
2197 EFI_PCI_IO_PASS_THROUGH_BAR,
2198 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
2199 1,
2200 &Address
2201 );
2202 }
2203
2204 /**
2205
2206 Read the four bit plane of VGA frame buffer
2207
2208
2209 @param PciIo - Pointer to PciIo protocol instance of the controller
2210 @param HardwareBuffer - Hardware VGA frame buffer address
2211 @param MemoryBuffer - Memory buffer address
2212 @param WidthInBytes - Number of bytes in a line to read
2213 @param Height - Height of the area to read
2214
2215 @return None
2216
2217 **/
2218 VOID
2219 VgaReadBitPlanes (
2220 EFI_PCI_IO_PROTOCOL *PciIo,
2221 UINT8 *HardwareBuffer,
2222 UINT8 *MemoryBuffer,
2223 UINTN WidthInBytes,
2224 UINTN Height
2225 )
2226 {
2227 UINTN BitPlane;
2228 UINTN Rows;
2229 UINTN FrameBufferOffset;
2230 UINT8 *Source;
2231 UINT8 *Destination;
2232
2233 //
2234 // Program the Mode Register Write mode 0, Read mode 0
2235 //
2236 WriteGraphicsController (
2237 PciIo,
2238 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2239 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2240 );
2241
2242 for (BitPlane = 0, FrameBufferOffset = 0;
2243 BitPlane < VGA_NUMBER_OF_BIT_PLANES;
2244 BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
2245 ) {
2246 //
2247 // Program the Read Map Select Register to select the correct bit plane
2248 //
2249 WriteGraphicsController (
2250 PciIo,
2251 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
2252 BitPlane
2253 );
2254
2255 Source = HardwareBuffer;
2256 Destination = MemoryBuffer + FrameBufferOffset;
2257
2258 for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
2259 PciIo->Mem.Read (
2260 PciIo,
2261 EfiPciIoWidthUint8,
2262 (UINT8) EFI_PCI_IO_PASS_THROUGH_BAR,
2263 (UINT64)(UINTN) Source,
2264 WidthInBytes,
2265 (VOID *) Destination
2266 );
2267 }
2268 }
2269 }
2270
2271 /**
2272
2273 Internal routine to convert VGA color to Grahpics Output color
2274
2275
2276 @param MemoryBuffer - Buffer containing VGA color
2277 @param X - The X coordinate of pixel on screen
2278 @param Y - The Y coordinate of pixel on screen
2279 @param BltBuffer - Buffer to contain converted Grahpics Output color
2280
2281 @return None
2282
2283 **/
2284 VOID
2285 VgaConvertToGraphicsOutputColor (
2286 UINT8 *MemoryBuffer,
2287 UINTN X,
2288 UINTN Y,
2289 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2290 )
2291 {
2292 UINTN Mask;
2293 UINTN Bit;
2294 UINTN Color;
2295
2296 MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3));
2297 Mask = mVgaBitMaskTable[X & 0x07];
2298 for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
2299 if (*MemoryBuffer & Mask) {
2300 Color |= Bit;
2301 }
2302 }
2303
2304 *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
2305 }
2306
2307 /**
2308
2309 Internal routine to convert Grahpics Output color to VGA color
2310
2311
2312 @param BltBuffer - buffer containing Grahpics Output color
2313
2314 @return Converted VGA color
2315
2316 **/
2317 UINT8
2318 VgaConvertColor (
2319 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
2320 )
2321 {
2322 UINT8 Color;
2323
2324 Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
2325 if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
2326 Color |= 0x08;
2327 }
2328
2329 return Color;
2330 }
2331
2332 /**
2333 Grahpics Output protocol instance to block transfer for VGA device
2334
2335 @param This Pointer to Grahpics Output protocol instance
2336 @param BltBuffer The data to transfer to screen
2337 @param BltOperation The operation to perform
2338 @param SourceX The X coordinate of the source for BltOperation
2339 @param SourceY The Y coordinate of the source for BltOperation
2340 @param DestinationX The X coordinate of the destination for BltOperation
2341 @param DestinationY The Y coordinate of the destination for BltOperation
2342 @param Width The width of a rectangle in the blt rectangle in pixels
2343 @param Height The height of a rectangle in the blt rectangle in pixels
2344 @param Delta Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
2345 If a Delta of 0 is used, the entire BltBuffer will be operated on.
2346 If a subrectangle of the BltBuffer is used, then Delta represents
2347 the number of bytes in a row of the BltBuffer.
2348
2349 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2350 @retval EFI_SUCCESS Blt operation success
2351
2352 **/
2353 EFI_STATUS
2354 EFIAPI
2355 BiosVideoGraphicsOutputVgaBlt (
2356 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
2357 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
2358 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
2359 IN UINTN SourceX,
2360 IN UINTN SourceY,
2361 IN UINTN DestinationX,
2362 IN UINTN DestinationY,
2363 IN UINTN Width,
2364 IN UINTN Height,
2365 IN UINTN Delta
2366 )
2367 {
2368 BIOS_VIDEO_DEV *BiosVideoPrivate;
2369 EFI_TPL OriginalTPL;
2370 UINT8 *MemAddress;
2371 UINTN BytesPerScanLine;
2372 //UINTN BytesPerBitPlane;
2373 UINTN Bit;
2374 UINTN Index;
2375 UINTN Index1;
2376 UINTN StartAddress;
2377 UINTN Bytes;
2378 UINTN Offset;
2379 UINT8 LeftMask;
2380 UINT8 RightMask;
2381 UINTN Address;
2382 UINTN AddressFix;
2383 UINT8 *Address1;
2384 UINT8 *SourceAddress;
2385 UINT8 *DestinationAddress;
2386 EFI_PCI_IO_PROTOCOL *PciIo;
2387 UINT8 Data;
2388 UINT8 PixelColor;
2389 UINT8 *VgaFrameBuffer;
2390 UINTN SourceOffset;
2391 UINTN SourceWidth;
2392 UINTN Rows;
2393 UINTN Columns;
2394 UINTN X;
2395 UINTN Y;
2396 UINTN CurrentMode;
2397
2398 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
2399
2400 CurrentMode = This->Mode->Mode;
2401 PciIo = BiosVideoPrivate->PciIo;
2402 MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
2403 BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
2404 //BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution;
2405 VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
2406
2407 if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
2408 return EFI_INVALID_PARAMETER;
2409 }
2410
2411 if (Width == 0 || Height == 0) {
2412 return EFI_INVALID_PARAMETER;
2413 }
2414 //
2415 // We need to fill the Virtual Screen buffer with the blt data.
2416 // The virtual screen is upside down, as the first row is the bootom row of
2417 // the image.
2418 //
2419 if (BltOperation == EfiBltVideoToBltBuffer) {
2420 //
2421 // Video to BltBuffer: Source is Video, destination is BltBuffer
2422 //
2423 if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2424 return EFI_INVALID_PARAMETER;
2425 }
2426
2427 if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2428 return EFI_INVALID_PARAMETER;
2429 }
2430 } else {
2431 //
2432 // BltBuffer to Video: Source is BltBuffer, destination is Video
2433 //
2434 if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
2435 return EFI_INVALID_PARAMETER;
2436 }
2437
2438 if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
2439 return EFI_INVALID_PARAMETER;
2440 }
2441 }
2442 //
2443 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2444 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2445 // the number of bytes in each row can be computed.
2446 //
2447 if (Delta == 0) {
2448 Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
2449 }
2450 //
2451 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2452 // We would not want a timer based event (Cursor, ...) to come in while we are
2453 // doing this operation.
2454 //
2455 OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
2456
2457 //
2458 // Compute some values we need for VGA
2459 //
2460 switch (BltOperation) {
2461 case EfiBltVideoToBltBuffer:
2462
2463 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2464 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2465
2466 //
2467 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2468 //
2469 VgaReadBitPlanes (
2470 PciIo,
2471 MemAddress + SourceOffset,
2472 VgaFrameBuffer + SourceOffset,
2473 SourceWidth,
2474 Height
2475 );
2476
2477 //
2478 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2479 //
2480 BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
2481 for (Rows = 0, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) {
2482 for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) {
2483 VgaConvertToGraphicsOutputColor (VgaFrameBuffer, X, Y, BltBuffer);
2484 }
2485
2486 BltBuffer -= Width;
2487 }
2488
2489 break;
2490
2491 case EfiBltVideoToVideo:
2492 //
2493 // Check for an aligned Video to Video operation
2494 //
2495 if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
2496 //
2497 // Program the Mode Register Write mode 1, Read mode 0
2498 //
2499 WriteGraphicsController (
2500 PciIo,
2501 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2502 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2503 );
2504
2505 SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
2506 DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2507 Bytes = Width >> 3;
2508 for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
2509 PciIo->CopyMem (
2510 PciIo,
2511 EfiPciIoWidthUint8,
2512 EFI_PCI_IO_PASS_THROUGH_BAR,
2513 (UINT64) ((UINTN)DestinationAddress + Offset),
2514 EFI_PCI_IO_PASS_THROUGH_BAR,
2515 (UINT64) ((UINTN)SourceAddress + Offset),
2516 Bytes
2517 );
2518 }
2519 } else {
2520 SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
2521 SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
2522
2523 //
2524 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2525 //
2526 VgaReadBitPlanes (
2527 PciIo,
2528 MemAddress + SourceOffset,
2529 VgaFrameBuffer + SourceOffset,
2530 SourceWidth,
2531 Height
2532 );
2533 }
2534
2535 break;
2536
2537 case EfiBltVideoFill:
2538 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2539 Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
2540 LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
2541 RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
2542 if (Bytes == 0) {
2543 LeftMask = (UINT8) (LeftMask & RightMask);
2544 RightMask = 0;
2545 }
2546
2547 if (LeftMask == 0xff) {
2548 StartAddress--;
2549 Bytes++;
2550 LeftMask = 0;
2551 }
2552
2553 if (RightMask == 0xff) {
2554 Bytes++;
2555 RightMask = 0;
2556 }
2557
2558 PixelColor = VgaConvertColor (BltBuffer);
2559
2560 //
2561 // Program the Mode Register Write mode 2, Read mode 0
2562 //
2563 WriteGraphicsController (
2564 PciIo,
2565 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2566 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2567 );
2568
2569 //
2570 // Program the Data Rotate/Function Select Register to replace
2571 //
2572 WriteGraphicsController (
2573 PciIo,
2574 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2575 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2576 );
2577
2578 if (LeftMask != 0) {
2579 //
2580 // Program the BitMask register with the Left column mask
2581 //
2582 WriteGraphicsController (
2583 PciIo,
2584 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2585 LeftMask
2586 );
2587
2588 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2589 //
2590 // Read data from the bit planes into the latches
2591 //
2592 PciIo->Mem.Read (
2593 PciIo,
2594 EfiPciIoWidthUint8,
2595 EFI_PCI_IO_PASS_THROUGH_BAR,
2596 (UINT64) Address,
2597 1,
2598 &Data
2599 );
2600 //
2601 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2602 //
2603 PciIo->Mem.Write (
2604 PciIo,
2605 EfiPciIoWidthUint8,
2606 EFI_PCI_IO_PASS_THROUGH_BAR,
2607 (UINT64) Address,
2608 1,
2609 &PixelColor
2610 );
2611 }
2612 }
2613
2614 if (Bytes > 1) {
2615 //
2616 // Program the BitMask register with the middle column mask of 0xff
2617 //
2618 WriteGraphicsController (
2619 PciIo,
2620 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2621 0xff
2622 );
2623
2624 for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
2625 PciIo->Mem.Write (
2626 PciIo,
2627 EfiPciIoWidthFillUint8,
2628 EFI_PCI_IO_PASS_THROUGH_BAR,
2629 (UINT64) Address,
2630 Bytes - 1,
2631 &PixelColor
2632 );
2633 }
2634 }
2635
2636 if (RightMask != 0) {
2637 //
2638 // Program the BitMask register with the Right column mask
2639 //
2640 WriteGraphicsController (
2641 PciIo,
2642 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2643 RightMask
2644 );
2645
2646 for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
2647 //
2648 // Read data from the bit planes into the latches
2649 //
2650 PciIo->Mem.Read (
2651 PciIo,
2652 EfiPciIoWidthUint8,
2653 EFI_PCI_IO_PASS_THROUGH_BAR,
2654 (UINT64) Address,
2655 1,
2656 &Data
2657 );
2658 //
2659 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2660 //
2661 PciIo->Mem.Write (
2662 PciIo,
2663 EfiPciIoWidthUint8,
2664 EFI_PCI_IO_PASS_THROUGH_BAR,
2665 (UINT64) Address,
2666 1,
2667 &PixelColor
2668 );
2669 }
2670 }
2671 break;
2672
2673 case EfiBltBufferToVideo:
2674 StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
2675 LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
2676
2677 //
2678 // Program the Mode Register Write mode 2, Read mode 0
2679 //
2680 WriteGraphicsController (
2681 PciIo,
2682 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
2683 VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2684 );
2685
2686 //
2687 // Program the Data Rotate/Function Select Register to replace
2688 //
2689 WriteGraphicsController (
2690 PciIo,
2691 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
2692 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2693 );
2694
2695 for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
2696 for (Index1 = 0; Index1 < Width; Index1++) {
2697 BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
2698 }
2699 AddressFix = Address;
2700
2701 for (Bit = 0; Bit < 8; Bit++) {
2702 //
2703 // Program the BitMask register with the Left column mask
2704 //
2705 WriteGraphicsController (
2706 PciIo,
2707 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
2708 LeftMask
2709 );
2710
2711 for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
2712 //
2713 // Read data from the bit planes into the latches
2714 //
2715 PciIo->Mem.Read (
2716 PciIo,
2717 EfiPciIoWidthUint8,
2718 EFI_PCI_IO_PASS_THROUGH_BAR,
2719 (UINT64)(UINTN) Address1,
2720 1,
2721 &Data
2722 );
2723
2724 PciIo->Mem.Write (
2725 PciIo,
2726 EfiPciIoWidthUint8,
2727 EFI_PCI_IO_PASS_THROUGH_BAR,
2728 (UINT64)(UINTN) Address1,
2729 1,
2730 &BiosVideoPrivate->LineBuffer[Index1]
2731 );
2732 }
2733
2734 LeftMask = (UINT8) (LeftMask >> 1);
2735 if (LeftMask == 0) {
2736 LeftMask = 0x80;
2737 AddressFix++;
2738 }
2739 }
2740 }
2741
2742 break;
2743 default:
2744 break;
2745 }
2746
2747 gBS->RestoreTPL (OriginalTPL);
2748
2749 return EFI_SUCCESS;
2750 }
2751 //
2752 // VGA Mini Port Protocol Functions
2753 //
2754 /**
2755 VgaMiniPort protocol interface to set mode
2756
2757 @param This Pointer to VgaMiniPort protocol instance
2758 @param ModeNumber The index of the mode
2759
2760 @retval EFI_UNSUPPORTED The requested mode is not supported
2761 @retval EFI_SUCCESS The requested mode is set successfully
2762
2763 **/
2764 EFI_STATUS
2765 EFIAPI
2766 BiosVideoVgaMiniPortSetMode (
2767 IN EFI_VGA_MINI_PORT_PROTOCOL *This,
2768 IN UINTN ModeNumber
2769 )
2770 {
2771 BIOS_VIDEO_DEV *BiosVideoPrivate;
2772 IA32_REGISTER_SET Regs;
2773
2774 if (This == NULL) {
2775 return EFI_INVALID_PARAMETER;
2776 }
2777
2778 //
2779 // Make sure the ModeNumber is a valid value
2780 //
2781 if (ModeNumber >= This->MaxMode) {
2782 return EFI_UNSUPPORTED;
2783 }
2784 //
2785 // Get the device structure for this device
2786 //
2787 BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
2788
2789 gBS->SetMem (&Regs, sizeof (Regs), 0);
2790
2791 switch (ModeNumber) {
2792 case 0:
2793 //
2794 // Set the 80x25 Text VGA Mode
2795 //
2796 Regs.H.AH = 0x00;
2797 Regs.H.AL = 0x83;
2798 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
2799
2800 Regs.H.AH = 0x11;
2801 Regs.H.AL = 0x14;
2802 Regs.H.BL = 0;
2803 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
2804
2805 break;
2806
2807 case 1:
2808 //
2809 // Set the 80x50 Text VGA Mode
2810 //
2811 Regs.H.AH = 0x00;
2812 Regs.H.AL = 0x83;
2813 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
2814
2815 Regs.H.AH = 0x11;
2816 Regs.H.AL = 0x12;
2817 Regs.H.BL = 0;
2818 LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs);
2819 break;
2820
2821 default:
2822 return EFI_UNSUPPORTED;
2823 }
2824
2825 return EFI_SUCCESS;
2826 }