1 /** @file
2
3 This driver produces Virtio Device Protocol instances for Virtio PCI devices.
4
5 Copyright (C) 2012, Red Hat, Inc.
6 Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
7 Copyright (C) 2013, ARM Ltd.
8
9 This program and the accompanying materials are licensed and made available
10 under the terms and conditions of the BSD License which accompanies this
11 distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
15 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include <IndustryStandard/Pci.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/UefiLib.h>
25
26 #include "VirtioPciDevice.h"
27
28 STATIC VIRTIO_DEVICE_PROTOCOL mDeviceProtocolTemplate = {
29 0, // Revision
30 0, // SubSystemDeviceId
31 VirtioPciGetDeviceFeatures, // GetDeviceFeatures
32 VirtioPciSetGuestFeatures, // SetGuestFeatures
33 VirtioPciSetQueueAddress, // SetQueueAddress
34 VirtioPciSetQueueSel, // SetQueueSel
35 VirtioPciSetQueueNotify, // SetQueueNotify
36 VirtioPciSetQueueAlignment, // SetQueueAlignment
37 VirtioPciSetPageSize, // SetPageSize
38 VirtioPciGetQueueSize, // GetQueueNumMax
39 VirtioPciSetQueueSize, // SetQueueNum
40 VirtioPciGetDeviceStatus, // GetDeviceStatus
41 VirtioPciSetDeviceStatus, // SetDeviceStatus
42 VirtioPciDeviceWrite, // WriteDevice
43 VirtioPciDeviceRead // ReadDevice
44 };
45
46 /**
47
48 Read a word from Region 0 of the device specified by PciIo.
49
50 Region 0 must be an iomem region. This is an internal function for the PCI
51 implementation of the protocol.
52
53 @param[in] Dev Virtio PCI device.
54
55 @param[in] FieldOffset Source offset.
56
57 @param[in] FieldSize Source field size, must be in { 1, 2, 4, 8 }.
58
59 @param[in] BufferSize Number of bytes available in the target buffer. Must
60 equal FieldSize.
61
62 @param[out] Buffer Target buffer.
63
64
65 @return Status code returned by PciIo->Io.Read().
66
67 **/
68 EFI_STATUS
69 EFIAPI
VirtioPciIoRead(IN VIRTIO_PCI_DEVICE * Dev,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINTN BufferSize,OUT VOID * Buffer)70 VirtioPciIoRead (
71 IN VIRTIO_PCI_DEVICE *Dev,
72 IN UINTN FieldOffset,
73 IN UINTN FieldSize,
74 IN UINTN BufferSize,
75 OUT VOID *Buffer
76 )
77 {
78 UINTN Count;
79 EFI_PCI_IO_PROTOCOL_WIDTH Width;
80 EFI_PCI_IO_PROTOCOL *PciIo;
81
82 ASSERT (FieldSize == BufferSize);
83
84 PciIo = Dev->PciIo;
85 Count = 1;
86
87 switch (FieldSize) {
88 case 1:
89 Width = EfiPciIoWidthUint8;
90 break;
91
92 case 2:
93 Width = EfiPciIoWidthUint16;
94 break;
95
96 case 8:
97 //
98 // The 64bit PCI I/O is broken down into two 32bit reads to prevent
99 // any alignment or width issues.
100 // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():
101 //
102 // The I/O operations are carried out exactly as requested. The caller
103 // is responsible for any alignment and I/O width issues which the
104 // bus, device, platform, or type of I/O might require. For example on
105 // some platforms, width requests of EfiPciIoWidthUint64 do not work.
106 //
107 Count = 2;
108
109 //
110 // fall through
111 //
112 case 4:
113 Width = EfiPciIoWidthUint32;
114 break;
115
116 default:
117 ASSERT (FALSE);
118 return EFI_INVALID_PARAMETER;
119 }
120
121 return PciIo->Io.Read (
122 PciIo,
123 Width,
124 PCI_BAR_IDX0,
125 FieldOffset,
126 Count,
127 Buffer
128 );
129 }
130
131 /**
132
133 Write a word into Region 0 of the device specified by PciIo.
134
135 Region 0 must be an iomem region. This is an internal function for the PCI
136 implementation of the protocol.
137
138 @param[in] Dev Virtio PCI device.
139
140 @param[in] FieldOffset Destination offset.
141
142 @param[in] FieldSize Destination field size, must be in { 1, 2, 4, 8 }.
143
144 @param[in] Value Little endian value to write, converted to UINT64.
145 The least significant FieldSize bytes will be used.
146
147
148 @return Status code returned by PciIo->Io.Write().
149
150 **/
151 EFI_STATUS
152 EFIAPI
VirtioPciIoWrite(IN VIRTIO_PCI_DEVICE * Dev,IN UINTN FieldOffset,IN UINTN FieldSize,IN UINT64 Value)153 VirtioPciIoWrite (
154 IN VIRTIO_PCI_DEVICE *Dev,
155 IN UINTN FieldOffset,
156 IN UINTN FieldSize,
157 IN UINT64 Value
158 )
159 {
160 UINTN Count;
161 EFI_PCI_IO_PROTOCOL_WIDTH Width;
162 EFI_PCI_IO_PROTOCOL *PciIo;
163
164 PciIo = Dev->PciIo;
165 Count = 1;
166
167 switch (FieldSize) {
168 case 1:
169 Width = EfiPciIoWidthUint8;
170 break;
171
172 case 2:
173 Width = EfiPciIoWidthUint16;
174 break;
175
176 case 8:
177 //
178 // The 64bit PCI I/O is broken down into two 32bit writes to prevent
179 // any alignment or width issues.
180 // The UEFI spec says under EFI_PCI_IO_PROTOCOL.Io.Write():
181 //
182 // The I/O operations are carried out exactly as requested. The caller
183 // is responsible for any alignment and I/O width issues which the
184 // bus, device, platform, or type of I/O might require. For example on
185 // some platforms, width requests of EfiPciIoWidthUint64 do not work
186 //
187 Count = Count * 2;
188
189 //
190 // fall through
191 //
192 case 4:
193 Width = EfiPciIoWidthUint32;
194 break;
195
196 default:
197 ASSERT (FALSE);
198 return EFI_INVALID_PARAMETER;
199 }
200
201 return PciIo->Io.Write (
202 PciIo,
203 Width,
204 PCI_BAR_IDX0,
205 FieldOffset,
206 Count,
207 &Value
208 );
209 }
210
211 /**
212
213 Device probe function for this driver.
214
215 The DXE core calls this function for any given device in order to see if the
216 driver can drive the device.
217
218 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
219 incorporating this driver (independently of
220 any device).
221
222 @param[in] DeviceHandle The device to probe.
223
224 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
225
226
227 @retval EFI_SUCCESS The driver supports the device being probed.
228
229 @retval EFI_UNSUPPORTED Based on virtio-pci discovery, we do not support
230 the device.
231
232 @return Error codes from the OpenProtocol() boot service or
233 the PciIo protocol.
234
235 **/
236 STATIC
237 EFI_STATUS
238 EFIAPI
VirtioPciDeviceBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)239 VirtioPciDeviceBindingSupported (
240 IN EFI_DRIVER_BINDING_PROTOCOL *This,
241 IN EFI_HANDLE DeviceHandle,
242 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
243 )
244 {
245 EFI_STATUS Status;
246 EFI_PCI_IO_PROTOCOL *PciIo;
247 PCI_TYPE00 Pci;
248
249 //
250 // Attempt to open the device with the PciIo set of interfaces. On success,
251 // the protocol is "instantiated" for the PCI device. Covers duplicate open
252 // attempts (EFI_ALREADY_STARTED).
253 //
254 Status = gBS->OpenProtocol (
255 DeviceHandle, // candidate device
256 &gEfiPciIoProtocolGuid, // for generic PCI access
257 (VOID **)&PciIo, // handle to instantiate
258 This->DriverBindingHandle, // requestor driver identity
259 DeviceHandle, // ControllerHandle, according to
260 // the UEFI Driver Model
261 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to
262 // the device; to be released
263 );
264 if (EFI_ERROR (Status)) {
265 return Status;
266 }
267
268 //
269 // Read entire PCI configuration header for more extensive check ahead.
270 //
271 Status = PciIo->Pci.Read (
272 PciIo, // (protocol, device)
273 // handle
274 EfiPciIoWidthUint32, // access width & copy
275 // mode
276 0, // Offset
277 sizeof Pci / sizeof (UINT32), // Count
278 &Pci // target buffer
279 );
280
281 if (Status == EFI_SUCCESS) {
282 //
283 // virtio-0.9.5, 2.1 PCI Discovery
284 //
285 if ((Pci.Hdr.VendorId == VIRTIO_VENDOR_ID) &&
286 (Pci.Hdr.DeviceId >= 0x1000) &&
287 (Pci.Hdr.DeviceId <= 0x103F) &&
288 (Pci.Hdr.RevisionID == 0x00)) {
289 Status = EFI_SUCCESS;
290 } else {
291 Status = EFI_UNSUPPORTED;
292 }
293 }
294
295 //
296 // We needed PCI IO access only transitorily, to see whether we support the
297 // device or not.
298 //
299 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
300 This->DriverBindingHandle, DeviceHandle);
301
302 return Status;
303 }
304
305 /**
306
307 Initialize the VirtIo PCI Device
308
309 @param[in, out] Dev The driver instance to configure. The caller is
310 responsible for Device->PciIo's validity (ie. working IO
311 access to the underlying virtio-pci device).
312
313 @retval EFI_SUCCESS Setup complete.
314
315 @retval EFI_UNSUPPORTED The underlying IO device doesn't support the
316 provided address offset and read size.
317
318 @return Error codes from PciIo->Pci.Read().
319
320 **/
321 STATIC
322 EFI_STATUS
323 EFIAPI
VirtioPciInit(IN OUT VIRTIO_PCI_DEVICE * Device)324 VirtioPciInit (
325 IN OUT VIRTIO_PCI_DEVICE *Device
326 )
327 {
328 EFI_STATUS Status;
329 EFI_PCI_IO_PROTOCOL *PciIo;
330 PCI_TYPE00 Pci;
331
332 ASSERT (Device != NULL);
333 PciIo = Device->PciIo;
334 ASSERT (PciIo != NULL);
335 ASSERT (PciIo->Pci.Read != NULL);
336
337 Status = PciIo->Pci.Read (
338 PciIo, // (protocol, device)
339 // handle
340 EfiPciIoWidthUint32, // access width & copy
341 // mode
342 0, // Offset
343 sizeof (Pci) / sizeof (UINT32), // Count
344 &Pci // target buffer
345 );
346 if (EFI_ERROR (Status)) {
347 return Status;
348 }
349
350 //
351 // Copy protocol template
352 //
353 CopyMem (&Device->VirtioDevice, &mDeviceProtocolTemplate,
354 sizeof (VIRTIO_DEVICE_PROTOCOL));
355
356 //
357 // Initialize the protocol interface attributes
358 //
359 Device->VirtioDevice.Revision = VIRTIO_SPEC_REVISION (0, 9, 5);
360 Device->VirtioDevice.SubSystemDeviceId = Pci.Device.SubsystemID;
361
362 //
363 // Note: We don't support the MSI-X capability. If we did,
364 // the offset would become 24 after enabling MSI-X.
365 //
366 Device->DeviceSpecificConfigurationOffset =
367 VIRTIO_DEVICE_SPECIFIC_CONFIGURATION_OFFSET_PCI;
368
369 return EFI_SUCCESS;
370 }
371
372 /**
373
374 Uninitialize the internals of a virtio-pci device that has been successfully
375 set up with VirtioPciInit().
376
377 @param[in, out] Dev The device to clean up.
378
379 **/
380
381 STATIC
382 VOID
383 EFIAPI
VirtioPciUninit(IN OUT VIRTIO_PCI_DEVICE * Device)384 VirtioPciUninit (
385 IN OUT VIRTIO_PCI_DEVICE *Device
386 )
387 {
388 // Note: This function mirrors VirtioPciInit() that does not allocate any
389 // resources - there's nothing to free here.
390 }
391
392 /**
393
394 After we've pronounced support for a specific device in
395 DriverBindingSupported(), we start managing said device (passed in by the
396 Driver Execution Environment) with the following service.
397
398 See DriverBindingSupported() for specification references.
399
400 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
401 incorporating this driver (independently of
402 any device).
403
404 @param[in] DeviceHandle The supported device to drive.
405
406 @param[in] RemainingDevicePath Relevant only for bus drivers, ignored.
407
408
409 @retval EFI_SUCCESS Driver instance has been created and
410 initialized for the virtio-pci device, it
411 is now accessible via VIRTIO_DEVICE_PROTOCOL.
412
413 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
414
415 @return Error codes from the OpenProtocol() boot
416 service, the PciIo protocol, VirtioPciInit(),
417 or the InstallProtocolInterface() boot service.
418
419 **/
420 STATIC
421 EFI_STATUS
422 EFIAPI
VirtioPciDeviceBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)423 VirtioPciDeviceBindingStart (
424 IN EFI_DRIVER_BINDING_PROTOCOL *This,
425 IN EFI_HANDLE DeviceHandle,
426 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
427 )
428 {
429 VIRTIO_PCI_DEVICE *Device;
430 EFI_STATUS Status;
431
432 Device = (VIRTIO_PCI_DEVICE *) AllocateZeroPool (sizeof *Device);
433 if (Device == NULL) {
434 return EFI_OUT_OF_RESOURCES;
435 }
436
437 Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
438 (VOID **)&Device->PciIo, This->DriverBindingHandle,
439 DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
440 if (EFI_ERROR (Status)) {
441 goto FreeVirtioPci;
442 }
443
444 //
445 // We must retain and ultimately restore the original PCI attributes of the
446 // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers /
447 // 18.3.2 Start() and Stop().
448 //
449 // The third parameter ("Attributes", input) is ignored by the Get operation.
450 // The fourth parameter ("Result", output) is ignored by the Enable and Set
451 // operations.
452 //
453 // For virtio-pci we only need IO space access.
454 //
455 Status = Device->PciIo->Attributes (Device->PciIo,
456 EfiPciIoAttributeOperationGet, 0, &Device->OriginalPciAttributes);
457 if (EFI_ERROR (Status)) {
458 goto ClosePciIo;
459 }
460
461 Status = Device->PciIo->Attributes (Device->PciIo,
462 EfiPciIoAttributeOperationEnable,
463 EFI_PCI_IO_ATTRIBUTE_IO, NULL);
464 if (EFI_ERROR (Status)) {
465 goto ClosePciIo;
466 }
467
468 //
469 // PCI IO access granted, configure protocol instance
470 //
471
472 Status = VirtioPciInit (Device);
473 if (EFI_ERROR (Status)) {
474 goto RestorePciAttributes;
475 }
476
477 //
478 // Setup complete, attempt to export the driver instance's VirtioDevice
479 // interface.
480 //
481 Device->Signature = VIRTIO_PCI_DEVICE_SIGNATURE;
482 Status = gBS->InstallProtocolInterface (&DeviceHandle,
483 &gVirtioDeviceProtocolGuid, EFI_NATIVE_INTERFACE,
484 &Device->VirtioDevice);
485 if (EFI_ERROR (Status)) {
486 goto UninitDev;
487 }
488
489 return EFI_SUCCESS;
490
491 UninitDev:
492 VirtioPciUninit (Device);
493
494 RestorePciAttributes:
495 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
496 Device->OriginalPciAttributes, NULL);
497
498 ClosePciIo:
499 gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
500 This->DriverBindingHandle, DeviceHandle);
501
502 FreeVirtioPci:
503 FreePool (Device);
504
505 return Status;
506 }
507
508 /**
509
510 Stop driving the Virtio PCI device
511
512 @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object
513 incorporating this driver (independently of any
514 device).
515
516 @param[in] DeviceHandle Stop driving this device.
517
518 @param[in] NumberOfChildren Since this function belongs to a device driver
519 only (as opposed to a bus driver), the caller
520 environment sets NumberOfChildren to zero, and
521 we ignore it.
522
523 @param[in] ChildHandleBuffer Ignored (corresponding to NumberOfChildren).
524
525 @retval EFI_SUCCESS Driver instance has been stopped and the PCI
526 configuration attributes have been restored.
527
528 @return Error codes from the OpenProtocol() or
529 CloseProtocol(), UninstallProtocolInterface()
530 boot services.
531
532 **/
533 STATIC
534 EFI_STATUS
535 EFIAPI
VirtioPciDeviceBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)536 VirtioPciDeviceBindingStop (
537 IN EFI_DRIVER_BINDING_PROTOCOL *This,
538 IN EFI_HANDLE DeviceHandle,
539 IN UINTN NumberOfChildren,
540 IN EFI_HANDLE *ChildHandleBuffer
541 )
542 {
543 EFI_STATUS Status;
544 VIRTIO_DEVICE_PROTOCOL *VirtioDevice;
545 VIRTIO_PCI_DEVICE *Device;
546
547 Status = gBS->OpenProtocol (
548 DeviceHandle, // candidate device
549 &gVirtioDeviceProtocolGuid, // retrieve the VirtIo iface
550 (VOID **)&VirtioDevice, // target pointer
551 This->DriverBindingHandle, // requestor driver identity
552 DeviceHandle, // requesting lookup for dev.
553 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no ref. added
554 );
555 if (EFI_ERROR (Status)) {
556 return Status;
557 }
558
559 Device = VIRTIO_PCI_DEVICE_FROM_VIRTIO_DEVICE (VirtioDevice);
560
561 //
562 // Handle Stop() requests for in-use driver instances gracefully.
563 //
564 Status = gBS->UninstallProtocolInterface (DeviceHandle,
565 &gVirtioDeviceProtocolGuid, &Device->VirtioDevice);
566 if (EFI_ERROR (Status)) {
567 return Status;
568 }
569
570 VirtioPciUninit (Device);
571
572 Device->PciIo->Attributes (Device->PciIo, EfiPciIoAttributeOperationSet,
573 Device->OriginalPciAttributes, NULL);
574
575 Status = gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid,
576 This->DriverBindingHandle, DeviceHandle);
577
578 FreePool (Device);
579
580 return Status;
581 }
582
583
584 //
585 // The static object that groups the Supported() (ie. probe), Start() and
586 // Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
587 // C, 10.1 EFI Driver Binding Protocol.
588 //
589 STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
590 &VirtioPciDeviceBindingSupported,
591 &VirtioPciDeviceBindingStart,
592 &VirtioPciDeviceBindingStop,
593 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
594 NULL, // ImageHandle, to be overwritten by
595 // EfiLibInstallDriverBindingComponentName2() in VirtioPciEntryPoint()
596 NULL // DriverBindingHandle, ditto
597 };
598
599
600 //
601 // The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
602 // EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
603 // in English, for display on standard console devices. This is recommended for
604 // UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
605 // Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
606 //
607 STATIC
608 EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
609 { "eng;en", L"Virtio PCI Driver" },
610 { NULL, NULL }
611 };
612
613 STATIC
614 EFI_COMPONENT_NAME_PROTOCOL gComponentName;
615
616 EFI_STATUS
617 EFIAPI
VirtioPciGetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN CHAR8 * Language,OUT CHAR16 ** DriverName)618 VirtioPciGetDriverName (
619 IN EFI_COMPONENT_NAME_PROTOCOL *This,
620 IN CHAR8 *Language,
621 OUT CHAR16 **DriverName
622 )
623 {
624 return LookupUnicodeString2 (
625 Language,
626 This->SupportedLanguages,
627 mDriverNameTable,
628 DriverName,
629 (BOOLEAN)(This == &gComponentName) // Iso639Language
630 );
631 }
632
633 EFI_STATUS
634 EFIAPI
VirtioPciGetDeviceName(IN EFI_COMPONENT_NAME_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN EFI_HANDLE ChildHandle,IN CHAR8 * Language,OUT CHAR16 ** ControllerName)635 VirtioPciGetDeviceName (
636 IN EFI_COMPONENT_NAME_PROTOCOL *This,
637 IN EFI_HANDLE DeviceHandle,
638 IN EFI_HANDLE ChildHandle,
639 IN CHAR8 *Language,
640 OUT CHAR16 **ControllerName
641 )
642 {
643 return EFI_UNSUPPORTED;
644 }
645
646 STATIC
647 EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
648 &VirtioPciGetDriverName,
649 &VirtioPciGetDeviceName,
650 "eng" // SupportedLanguages, ISO 639-2 language codes
651 };
652
653 STATIC
654 EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
655 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) &VirtioPciGetDriverName,
656 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &VirtioPciGetDeviceName,
657 "en" // SupportedLanguages, RFC 4646 language codes
658 };
659
660
661 //
662 // Entry point of this driver.
663 //
664 EFI_STATUS
665 EFIAPI
VirtioPciDeviceEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)666 VirtioPciDeviceEntryPoint (
667 IN EFI_HANDLE ImageHandle,
668 IN EFI_SYSTEM_TABLE *SystemTable
669 )
670 {
671 return EfiLibInstallDriverBindingComponentName2 (
672 ImageHandle,
673 SystemTable,
674 &gDriverBinding,
675 ImageHandle,
676 &gComponentName,
677 &gComponentName2
678 );
679 }
680