1
/* $Id: VBoxVgaMiniPortDxe.c $ */
3
* VBoxVgaMiniPortDxe.c - VgaMiniPort Protocol Implementation.
8
* Copyright (C) 2009-2010 Sun Microsystems, Inc.
10
* This file is part of VirtualBox Open Source Edition (OSE), as
11
* available from http://www.virtualbox.org. This file is free software;
12
* you can redistribute it and/or modify it under the terms of the GNU
13
* General Public License (GPL) as published by the Free Software
14
* Foundation, in version 2 as it comes in the "COPYING" file of the
15
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19
* Clara, CA 95054 USA or visit http://www.sun.com if you need
20
* additional information or have any questions.
24
/*******************************************************************************
26
*******************************************************************************/
27
#include <Protocol/ComponentName.h>
28
#include <Protocol/ComponentName2.h>
29
#include <Protocol/DriverBinding.h>
30
#include <Protocol/PciIo.h>
31
#include <Protocol/VgaMiniPort.h>
32
#include <Library/BaseMemoryLib.h>
33
#include <Library/DebugLib.h>
34
#include <Library/UefiBootServicesTableLib.h>
35
#include <Library/UefiLib.h>
36
#include <IndustryStandard/Pci22.h>
40
#include "VBoxVgaFonts.h"
43
/*******************************************************************************
44
* Structures and Typedefs *
45
*******************************************************************************/
47
* Instance data for a VGA device this driver handles.
49
typedef struct VBOXVGAMINIPORT
51
/** The VGA Mini Port Protocol. */
52
EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort;
53
/** Magic value, VBOX_VGA_MINI_PORT_MAGIC. */
55
/** The controller handle of the device. */
56
EFI_HANDLE hController;
57
/** The PciIo protocol for the device. */
58
EFI_PCI_IO_PROTOCOL *pPciIo;
60
/** Pointer to a VBOXVGAMINIPORT structure. */
61
typedef VBOXVGAMINIPORT *PVBOXVGAMINIPORT;
63
/** VBOXVGAMINIPORT::u32Magic value (Isaac Asimov). */
64
#define VBOX_VGA_MINI_PORT_MAGIC 0x19200102
65
/** VBOXVGAMINIPORT::u32Magic dead value. */
66
#define VBOX_VGA_MINI_PORT_MAGIC_DEAD 0x19920406
69
/*******************************************************************************
70
* Internal Functions *
71
*******************************************************************************/
72
static EFI_STATUS EFIAPI
73
VBoxVgaMiniPortDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
74
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
75
static EFI_STATUS EFIAPI
76
VBoxVgaMiniPortDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
77
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL);
78
static EFI_STATUS EFIAPI
79
VBoxVgaMiniPortDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
80
IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL);
83
static EFI_STATUS EFIAPI
84
VBoxVgaMiniPortVMP_SetMode(IN EFI_VGA_MINI_PORT_PROTOCOL *This, IN UINTN ModeNumber);
87
static EFI_STATUS EFIAPI
88
VBoxVgaMiniPortCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
89
IN CHAR8 *Language, OUT CHAR16 **DriverName);
90
static EFI_STATUS EFIAPI
91
VBoxVgaMiniPortCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
92
IN EFI_HANDLE ControllerHandle,
93
IN EFI_HANDLE ChildHandle OPTIONAL,
94
IN CHAR8 *Language, OUT CHAR16 **ControllerName);
97
static EFI_STATUS EFIAPI
98
VBoxVgaMiniPortCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
99
IN CHAR8 *Language, OUT CHAR16 **DriverName);
100
static EFI_STATUS EFIAPI
101
VBoxVgaMiniPortCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
102
IN EFI_HANDLE ControllerHandle,
103
IN EFI_HANDLE ChildHandle OPTIONAL,
104
IN CHAR8 *Language, OUT CHAR16 **ControllerName);
107
/*******************************************************************************
109
*******************************************************************************/
110
/** EFI Driver Binding Protocol. */
111
static EFI_DRIVER_BINDING_PROTOCOL g_VBoxVgaMiniPortDB =
113
VBoxVgaMiniPortDB_Supported,
114
VBoxVgaMiniPortDB_Start,
115
VBoxVgaMiniPortDB_Stop,
116
/* .Version = */ 1, /* One higher than Pci/VgaMiniPortDxe. */
117
/* .ImageHandle = */ NULL,
118
/* .DriverBindingHandle = */ NULL
121
/** EFI Component Name Protocol. */
122
static const EFI_COMPONENT_NAME_PROTOCOL g_VBoxVgaMiniPortCN =
124
VBoxVgaMiniPortCN_GetDriverName,
125
VBoxVgaMiniPortCN_GetControllerName,
129
/** EFI Component Name 2 Protocol. */
130
static const EFI_COMPONENT_NAME2_PROTOCOL g_VBoxVgaMiniPortCN2 =
132
VBoxVgaMiniPortCN2_GetDriverName,
133
VBoxVgaMiniPortCN2_GetControllerName,
137
/** Driver name translation table. */
138
static CONST EFI_UNICODE_STRING_TABLE g_aVBoxMiniPortDriverLangAndNames[] =
140
{ "eng;en", L"PCI VGA Mini Port Driver" },
147
* VBoxVgaMiniPort entry point.
149
* @returns EFI status code.
151
* @param ImageHandle The image handle.
152
* @param SystemTable The system table pointer.
155
DxeInitializeVBoxVgaMiniPort(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
158
DEBUG((DEBUG_INFO, "DxeInitializeVBoxVgaMiniPort\n"));
160
rc = EfiLibInstallDriverBindingComponentName2(ImageHandle, SystemTable,
161
&g_VBoxVgaMiniPortDB, ImageHandle,
162
&g_VBoxVgaMiniPortCN, &g_VBoxVgaMiniPortCN2);
163
ASSERT_EFI_ERROR(rc);
168
* @copydoc EFI_DRIVER_BINDING_SUPPORTED
170
static EFI_STATUS EFIAPI
171
VBoxVgaMiniPortDB_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
172
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
174
EFI_STATUS rcRet = EFI_UNSUPPORTED;
175
EFI_PCI_IO_PROTOCOL *pPciIo;
178
DEBUG((DEBUG_INFO, "%a: Controller=%p\n", __FUNCTION__, ControllerHandle));
181
* To perform the test we need to check some PCI configuration registers,
182
* just read all the standard ones to make life simpler.
184
rc = gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&pPciIo,
185
This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
190
rc = pPciIo->Pci.Read(pPciIo,
193
sizeof(CfgRegs) / sizeof(UINT32) /* Count */ ,
200
if (IS_PCI_VGA(&CfgRegs))
202
#if 0 /** @todo this doesn't quite work with our DevVGA since it doesn't flag I/O access. */
203
if ( CfgRegs.Hdr.Command & (PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS)
204
== (PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS))
209
DEBUG((DEBUG_INFO, "%a: Found supported VGA device! (VendorId=%x DeviceId=%x)\n",
210
__FUNCTION__, CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
214
DEBUG((DEBUG_INFO, "%a: VGA device not enabled! (VendorId=%x DeviceId=%x)\n",
215
__FUNCTION__, CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
218
DEBUG((DEBUG_INFO, "%a: Not VGA (Class=%x,%x,%x VendorId=%x DeviceId=%x)\n",
219
__FUNCTION__, CfgRegs.Hdr.ClassCode[0], CfgRegs.Hdr.ClassCode[1],
220
CfgRegs.Hdr.ClassCode[2], CfgRegs.Hdr.VendorId, CfgRegs.Hdr.DeviceId));
223
DEBUG((DEBUG_INFO, "%a: pPciIo->Pci.Read -> %r\n", __FUNCTION__, rc));
225
gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
228
DEBUG((DEBUG_INFO, "%a: PciIoProtocol -> %r\n", __FUNCTION__, rc));
233
* @copydoc EFI_DRIVER_BINDING_START
235
static EFI_STATUS EFIAPI
236
VBoxVgaMiniPortDB_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
237
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL)
240
EFI_PCI_IO_PROTOCOL *pPciIo;
242
DEBUG((DEBUG_INFO, "%a\n", __FUNCTION__));
245
* We need the PCI I/O abstraction protocol.
247
rc = gBS->OpenProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, (VOID **)&pPciIo,
248
This->DriverBindingHandle, ControllerHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
252
* Allocate and initialize the instance data.
254
PVBOXVGAMINIPORT pThisDev;
255
rc = gBS->AllocatePool(EfiBootServicesData, sizeof(*pThisDev), (VOID **)&pThisDev);
258
pThisDev->VgaMiniPort.SetMode = VBoxVgaMiniPortVMP_SetMode;
259
pThisDev->VgaMiniPort.VgaMemoryOffset = 0x000b8000;
260
pThisDev->VgaMiniPort.CrtcAddressRegisterOffset = 0x03d4;
261
pThisDev->VgaMiniPort.CrtcDataRegisterOffset = 0x03d5;
262
pThisDev->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
263
pThisDev->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
264
pThisDev->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
265
pThisDev->VgaMiniPort.MaxMode = 2;
266
pThisDev->u32Magic = VBOX_VGA_MINI_PORT_MAGIC;
267
pThisDev->hController = ControllerHandle;
268
pThisDev->pPciIo = pPciIo;
271
* Register the VGA Mini Port Protocol.
273
rc = gBS->InstallMultipleProtocolInterfaces(&ControllerHandle,
274
&gEfiVgaMiniPortProtocolGuid, &pThisDev->VgaMiniPort,
278
DEBUG((DEBUG_INFO, "%a: Successfully started, pThisDev=%p ControllerHandle=%p\n",
279
__FUNCTION__, pThisDev, ControllerHandle));
283
DEBUG((DEBUG_INFO, "%a: InstallMultipleProtocolInterfaces -> %r\n", __FUNCTION__, rc));
284
gBS->FreePool(pThisDev);
287
DEBUG((DEBUG_INFO, "%a: AllocatePool -> %r\n", __FUNCTION__, rc));
289
gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid, This->DriverBindingHandle, ControllerHandle);
292
DEBUG((DEBUG_INFO, "%a: PciIoProtocol -> %r\n", __FUNCTION__, rc));
297
* @copydoc EFI_DRIVER_BINDING_STOP
299
static EFI_STATUS EFIAPI
300
VBoxVgaMiniPortDB_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This, IN EFI_HANDLE ControllerHandle,
301
IN UINTN NumberOfChildren, IN EFI_HANDLE *ChildHandleBuffer OPTIONAL)
304
PVBOXVGAMINIPORT pThisDev;
306
DEBUG((DEBUG_INFO, "%a: ControllerHandle=%p NumberOfChildren=%u\n", __FUNCTION__, ControllerHandle, NumberOfChildren));
309
* Get the miniport driver instance associated with the controller.
311
rc = gBS->OpenProtocol(ControllerHandle, &gEfiVgaMiniPortProtocolGuid,
312
(VOID **)&pThisDev, This->DriverBindingHandle,
313
ControllerHandle, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
316
ASSERT(pThisDev->u32Magic == VBOX_VGA_MINI_PORT_MAGIC);
317
ASSERT(pThisDev->hController == ControllerHandle);
318
if ( pThisDev->u32Magic == VBOX_VGA_MINI_PORT_MAGIC
319
&& pThisDev->hController == ControllerHandle)
322
* Uninstall the VgaMiniPort interface.
324
rc = gBS->UninstallProtocolInterface(ControllerHandle,
325
&gEfiVgaMiniPortProtocolGuid,
326
&pThisDev->VgaMiniPort);
330
* Invalidate and release sources associated with the device instance.
332
pThisDev->u32Magic = VBOX_VGA_MINI_PORT_MAGIC_DEAD;
333
gBS->FreePool(pThisDev);
337
DEBUG((DEBUG_INFO, "%a: UninstallProtocolInterface -> %r\n", __FUNCTION__, rc));
341
DEBUG((DEBUG_INFO, "%a: magic=%x/%x hController=%x/%x\n", __FUNCTION__,
342
pThisDev->u32Magic, VBOX_VGA_MINI_PORT_MAGIC,
343
pThisDev->hController, ControllerHandle));
344
rc = EFI_DEVICE_ERROR;
346
gBS->CloseProtocol(ControllerHandle, &gEfiPciIoProtocolGuid,
347
This->DriverBindingHandle, ControllerHandle);
350
DEBUG((DEBUG_INFO, "%a: VgaMiniPortProtocol -> %r\n", __FUNCTION__, rc));
359
* @copydoc EFI_VGA_MINI_PORT_SET_MODE
361
static EFI_STATUS EFIAPI
362
VBoxVgaMiniPortVMP_SetMode(IN EFI_VGA_MINI_PORT_PROTOCOL *This, IN UINTN ModeNumber)
364
PVBOXVGAMINIPORT pThisDev = (PVBOXVGAMINIPORT)This;
371
if (pThisDev->u32Magic != VBOX_VGA_MINI_PORT_MAGIC)
373
DEBUG((DEBUG_INFO, "%a: u32Magic=%x/%x\n", __FUNCTION__, pThisDev->u32Magic, VBOX_VGA_MINI_PORT_MAGIC));
374
return EFI_DEVICE_ERROR;
376
if (ModeNumber >= This->MaxMode)
378
DEBUG((DEBUG_INFO, "%a: ModeNumber=%d >= MaxMode=%d\n", __FUNCTION__, ModeNumber, This->MaxMode));
379
return EFI_UNSUPPORTED;
381
DEBUG((DEBUG_INFO, "%a: ModeNumber=%d\n", __FUNCTION__, ModeNumber));
383
/* some initialization */
384
ASMOutU8(0x3c2, 0xc3);
385
ASMOutU8(0x3c4, 0x04);
386
ASMOutU8(0x3c5, 0x02);
389
* inb(r63, 0x3da); // reset attr F/F
390
* outb(0x3c0, 0); // disable palette
391
* outb(0x3d4, 0x11); outb(0x3d5, 0); // unprotect crtc regs 0 - 7
393
r[63] = ASMInU8((UINTN)0x3da);
395
ASMOutU16(0x3d4, 0x0011);
397
#define BOUTB(count, aport, dport) \
399
for (i = 0 ; i < count; ++i) \
401
ASMOutU8((aport), (UINT8)i);\
402
ASMOutU8((dport), r[i]); \
407
* Reset and set sequencer registers
409
* r0 = 0x01; r1 = 0x00; r2 = 0x03; r3 = 0x00; r4 = 0x02;
410
* boutb(5, 0x3c4, 0x3c5);
417
BOUTB(5, 0x3c4, 0x3c5);
420
* set misc out register
425
* boutb(1, 0x3c4, 0x3c5); // enable sequencer
428
BOUTB(1, 0x3c4, 0x3c5);
430
/* set all crtc registers */
431
r[0] = 0x5f; r[1] = 0x4f; r[2] = 0x50; r[3] = 0x82;
432
r[4] = 0x55; r[5] = 0x81; r[6] = 0xbf; r[7] = 0x1f;
433
r[8] = 0x00; r[9] = 0x4f; r[10]= 0x0d; r[11]= 0x0e;
434
r[12]= 0x00; r[13]= 0x00; r[14]= 0x03; r[15]= 0xc0;
435
r[16]= 0x9c; r[17]= 0x0e; r[18]= 0x8f; r[19]= 0x28;
436
r[20]= 0x1f; r[21]= 0x96; r[22]= 0xb9; r[23]= 0xa3;
438
BOUTB(25, 0x3d4, 0x3d5);
440
/* set all graphics controller registers */
441
r[0]= 0x00; r[1]= 0x00; r[2]= 0x00; r[3]= 0x00;
442
r[4]= 0x00; r[5]= 0x10; r[6]= 0x0e; r[7]= 0x00;
444
BOUTB(9, 0x3ce, 0x3cf);
446
/* set all attribute registers */
447
r[63] = ASMInU8(0x3da); // reset flip/flop
448
r[0] = 0x00; r[1] = 0x01; r[2] = 0x02; r[3] = 0x03;
449
r[4] = 0x04; r[5] = 0x05; r[6] = 0x14; r[7] = 0x07;
450
r[8] = 0x38; r[9] = 0x39; r[10]= 0x3a; r[11]= 0x3b;
451
r[12]= 0x3c; r[13]= 0x3d; r[14]= 0x3e; r[15]= 0x3f;
452
r[16]= 0x0c; r[17]= 0x00; r[18]= 0x0f; r[19]= 0x08;
454
BOUTB(21, 0x3c0, 0x3c0);
455
ASMOutU8(0x3c0, 0x20); // re-enable palette
457
/* set all VBox extended registers */
459
BOUTB(1, 0x3c4, 0x3c5); // disable sequencer
461
ASMOutU16(0x1ce, 0x04); ASMOutU16(0x1cf, 0); // ENABLE
464
BOUTB(1, 0x3c4, 0x3c5); // enable sequencer
466
/* Load default values into the first 16 entries of the DAC */
468
static const UINT8 s_a3bVgaDac[64*3] =
536
for (i = 0; i < 64; ++i)
538
ASMOutU8(0x3c8, (UINT8)i);
539
ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 0]);
540
ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 1]);
541
ASMOutU8(0x3c9, s_a3bVgaDac[i*3 + 2]);
545
/* Load the appropriate font into the first map */
547
UINT8 const *pabFont;
548
unsigned offBase = 0;
551
switch (ModeNumber) {
552
case 0: // 80x25 mode, uses 8x16 font
553
pabFont = g_abVgaFont_8x16;
556
case 1: // 80x50 mode, uses 8x8 font
557
pabFont = g_abVgaFont_8x8;
561
ASSERT(0); // Valid mode numbers checked above
562
return EFI_UNSUPPORTED;
564
// Enable font map access
566
/* Write sequencer registers */
567
ASMOutU16(0x3c4, 0x0100);
568
ASMOutU16(0x3c4, 0x0402);
569
ASMOutU16(0x3c4, 0x0704);
570
ASMOutU16(0x3c4, 0x0300);
571
/* Write graphics controller registers */
572
ASMOutU16(0x3ce, 0x0204);
573
ASMOutU16(0x3ce, 0x0005);
574
ASMOutU16(0x3ce, 0x0406);
577
for (i = 0; i < 256; ++i)
579
int offChr = i * height;
580
int offDst = offBase + i * 32;
581
CopyMem((UINT8 *)0xA0000 + offDst, pabFont + offChr, height);
584
// Set the CRTC Maximum Scan Line register
585
ASMOutU16(0x3d4, 0x4009 | ((height - 1) << 8));
587
// Disable font map access again
589
/* Write sequencer registers */
590
ASMOutU16(0x3c4, 0x0100);
591
ASMOutU16(0x3c4, 0x0302);
592
ASMOutU16(0x3c4, 0x0304);
593
ASMOutU16(0x3c4, 0x0300);
594
/* Write graphics controller registers */
595
ASMOutU16(0x3ce, 0x0004);
596
ASMOutU16(0x3ce, 0x1005);
597
ASMOutU16(0x3ce, 0x0e06);
607
/** @copydoc EFI_COMPONENT_NAME_GET_DRIVER_NAME */
608
static EFI_STATUS EFIAPI
609
VBoxVgaMiniPortCN_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
610
IN CHAR8 *Language, OUT CHAR16 **DriverName)
612
return LookupUnicodeString2(Language,
613
This->SupportedLanguages,
614
&g_aVBoxMiniPortDriverLangAndNames[0],
619
/** @copydoc EFI_COMPONENT_NAME_GET_CONTROLLER_NAME */
620
static EFI_STATUS EFIAPI
621
VBoxVgaMiniPortCN_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
622
IN EFI_HANDLE ControllerHandle,
623
IN EFI_HANDLE ChildHandle OPTIONAL,
624
IN CHAR8 *Language, OUT CHAR16 **ControllerName)
626
/** @todo try query the protocol from the controller and forward the query. */
627
return EFI_UNSUPPORTED;
633
/** @copydoc EFI_COMPONENT_NAME2_GET_DRIVER_NAME */
634
static EFI_STATUS EFIAPI
635
VBoxVgaMiniPortCN2_GetDriverName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
636
IN CHAR8 *Language, OUT CHAR16 **DriverName)
638
return LookupUnicodeString2(Language,
639
This->SupportedLanguages,
640
&g_aVBoxMiniPortDriverLangAndNames[0],
645
/** @copydoc EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME */
646
static EFI_STATUS EFIAPI
647
VBoxVgaMiniPortCN2_GetControllerName(IN EFI_COMPONENT_NAME2_PROTOCOL *This,
648
IN EFI_HANDLE ControllerHandle,
649
IN EFI_HANDLE ChildHandle OPTIONAL,
650
IN CHAR8 *Language, OUT CHAR16 **ControllerName)
652
/** @todo try query the protocol from the controller and forward the query. */
653
return EFI_UNSUPPORTED;