]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/SioBusDxe/SioBusDxe.c
OvmfPkg/Csm/LegacyBiosDxe: Fix Legacy16GetTableAddress call for E820 data
[mirror_edk2.git] / OvmfPkg / SioBusDxe / SioBusDxe.c
1 /** @file
2 The SioBusDxe driver is used to create child devices on the ISA bus and
3 installs the Super I/O protocols on them.
4
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "SioBusDxe.h"
12
13 //
14 // SioBus Driver Binding Protocol
15 //
16 EFI_DRIVER_BINDING_PROTOCOL gSioBusDriverBinding = {
17 SioBusDriverBindingSupported,
18 SioBusDriverBindingStart,
19 SioBusDriverBindingStop,
20 0x10,
21 NULL,
22 NULL
23 };
24
25
26 /**
27 Tests to see if this driver supports a given controller. If a child device is
28 provided, it further tests to see if this driver supports creating a handle
29 for the specified child device.
30
31 This function checks to see if the driver specified by This supports the
32 device specified by ControllerHandle. Drivers will typically use the device
33 path attached to ControllerHandle and/or the services from the bus I/O
34 abstraction attached to ControllerHandle to determine if the driver supports
35 ControllerHandle. This function may be called many times during platform
36 initialization. In order to reduce boot times, the tests performed by this
37 function must be very small, and take as little time as possible to execute.
38 This function must not change the state of any hardware devices, and this
39 function must be aware that the device specified by ControllerHandle may
40 already be managed by the same driver or a different driver. This function
41 must match its calls to AllocatePages() with FreePages(), AllocatePool() with
42 FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
43 may have been previously started by the same driver, if a protocol is already
44 in the opened state, then it must not be closed with CloseProtocol(). This is
45 required to guarantee the state of ControllerHandle is not modified by this
46 function.
47
48 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
49 instance.
50 @param[in] ControllerHandle The handle of the controller to test. This
51 handle must support a protocol interface
52 that supplies an I/O abstraction to the
53 driver.
54 @param[in] RemainingDevicePath A pointer to the remaining portion of a
55 device path. This parameter is ignored by
56 device drivers, and is optional for bus
57 drivers. For bus drivers, if this parameter
58 is not NULL, then the bus driver must
59 determine if the bus controller specified by
60 ControllerHandle and the child controller
61 specified by RemainingDevicePath are both
62 supported by this bus driver.
63
64 @retval EFI_SUCCESS The device specified by ControllerHandle and
65 RemainingDevicePath is supported by the
66 driver specified by This.
67 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
68 RemainingDevicePath is already being managed
69 by the driver specified by This.
70 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
71 RemainingDevicePath is already being managed
72 by a different driver or an application that
73 requires exclusive access.
74 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
75 RemainingDevicePath is not supported by the
76 driver specified by This.
77
78 **/
79 EFI_STATUS
80 EFIAPI
81 SioBusDriverBindingSupported (
82 IN EFI_DRIVER_BINDING_PROTOCOL *This,
83 IN EFI_HANDLE Controller,
84 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
85 )
86 {
87 EFI_STATUS Status;
88 EFI_PCI_IO_PROTOCOL *PciIo;
89 PCI_TYPE00 Pci;
90 UINTN SegmentNumber;
91 UINTN BusNumber;
92 UINTN DeviceNumber;
93 UINTN FunctionNumber;
94
95 //
96 // Get PciIo protocol instance
97 //
98 Status = gBS->OpenProtocol (
99 Controller,
100 &gEfiPciIoProtocolGuid,
101 (VOID**)&PciIo,
102 This->DriverBindingHandle,
103 Controller,
104 EFI_OPEN_PROTOCOL_BY_DRIVER
105 );
106 if (EFI_ERROR(Status)) {
107 return Status;
108 }
109
110 Status = PciIo->Pci.Read (
111 PciIo,
112 EfiPciIoWidthUint32,
113 0,
114 sizeof(Pci) / sizeof(UINT32),
115 &Pci);
116
117 if (!EFI_ERROR (Status)) {
118 Status = EFI_UNSUPPORTED;
119 if ((Pci.Hdr.Command & 0x03) == 0x03) {
120 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {
121 //
122 // See if this is a standard PCI to ISA Bridge from the Base Code and
123 // Class Code
124 //
125 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {
126 Status = EFI_SUCCESS;
127 }
128
129 //
130 // See if this is an Intel PCI to ISA bridge in Positive Decode Mode
131 //
132 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE &&
133 Pci.Hdr.VendorId == 0x8086) {
134 //
135 // See if this is on Function #0 to avoid false positives on
136 // PCI_CLASS_BRIDGE_OTHER that has the same value as
137 // PCI_CLASS_BRIDGE_ISA_PDECODE
138 //
139 Status = PciIo->GetLocation (
140 PciIo,
141 &SegmentNumber,
142 &BusNumber,
143 &DeviceNumber,
144 &FunctionNumber
145 );
146 if (!EFI_ERROR (Status) && FunctionNumber == 0) {
147 Status = EFI_SUCCESS;
148 } else {
149 Status = EFI_UNSUPPORTED;
150 }
151 }
152 }
153 }
154 }
155
156 gBS->CloseProtocol (
157 Controller,
158 &gEfiPciIoProtocolGuid,
159 This->DriverBindingHandle,
160 Controller
161 );
162
163 return Status;
164 }
165
166 /**
167 Starts a device controller or a bus controller.
168
169 The Start() function is designed to be invoked from the EFI boot service
170 ConnectController(). As a result, much of the error checking on the
171 parameters to Start() has been moved into this common boot service. It is
172 legal to call Start() from other locations, but the following calling
173 restrictions must be followed or the system behavior will not be
174 deterministic.
175 1. ControllerHandle must be a valid EFI_HANDLE.
176 2. If RemainingDevicePath is not NULL, then it must be a pointer to a
177 naturally aligned EFI_DEVICE_PATH_PROTOCOL.
178 3. Prior to calling Start(), the Supported() function for the driver
179 specified by This must have been called with the same calling parameters,
180 and Supported() must have returned EFI_SUCCESS.
181
182 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
183 instance.
184 @param[in] ControllerHandle The handle of the controller to start. This
185 handle must support a protocol interface
186 that supplies an I/O abstraction to the
187 driver.
188 @param[in] RemainingDevicePath A pointer to the remaining portion of a
189 device path. This parameter is ignored by
190 device drivers, and is optional for bus
191 drivers. For a bus driver, if this parameter
192 is NULL, then handles for all the children
193 of Controller are created by this driver. If
194 this parameter is not NULL and the first
195 Device Path Node is not the End of Device
196 Path Node, then only the handle for the
197 child device specified by the first Device
198 Path Node of RemainingDevicePath is created
199 by this driver. If the first Device Path
200 Node of RemainingDevicePath is the End of
201 Device Path Node, no child handle is created
202 by this driver.
203
204 @retval EFI_SUCCESS The device was started.
205 @retval EFI_DEVICE_ERROR The device could not be started due to a
206 device error.
207 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
208 lack of resources.
209 @retval Others The driver failded to start the device.
210
211 **/
212 EFI_STATUS
213 EFIAPI
214 SioBusDriverBindingStart (
215 IN EFI_DRIVER_BINDING_PROTOCOL *This,
216 IN EFI_HANDLE Controller,
217 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
218 )
219 {
220 EFI_STATUS Status;
221 EFI_PCI_IO_PROTOCOL *PciIo;
222 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
223 UINT64 Supports;
224 UINT64 OriginalAttributes;
225 UINT64 Attributes;
226 BOOLEAN Enabled;
227 SIO_BUS_DRIVER_PRIVATE_DATA *Private;
228 UINT32 ChildDeviceNumber;
229
230 Enabled = FALSE;
231 Supports = 0;
232 OriginalAttributes = 0;
233 Private = NULL;
234
235 //
236 // Open the PCI I/O Protocol Interface
237 //
238 PciIo = NULL;
239 Status = gBS->OpenProtocol (
240 Controller,
241 &gEfiPciIoProtocolGuid,
242 (VOID**) &PciIo,
243 This->DriverBindingHandle,
244 Controller,
245 EFI_OPEN_PROTOCOL_BY_DRIVER
246 );
247 if (EFI_ERROR (Status)) {
248 return Status;
249 }
250
251 //
252 // Open Device Path Protocol
253 //
254 Status = gBS->OpenProtocol (
255 Controller,
256 &gEfiDevicePathProtocolGuid,
257 (VOID **) &ParentDevicePath,
258 This->DriverBindingHandle,
259 Controller,
260 EFI_OPEN_PROTOCOL_BY_DRIVER
261 );
262 if (EFI_ERROR (Status)) {
263 gBS->CloseProtocol (
264 Controller,
265 &gEfiPciIoProtocolGuid,
266 This->DriverBindingHandle,
267 Controller
268 );
269 return Status;
270 }
271
272 //
273 // Get supported PCI attributes
274 //
275 Status = PciIo->Attributes (
276 PciIo,
277 EfiPciIoAttributeOperationSupported,
278 0,
279 &Supports
280 );
281 if (EFI_ERROR (Status)) {
282 goto Done;
283 }
284
285 Supports &= (UINT64) (EFI_PCI_IO_ATTRIBUTE_ISA_IO |
286 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
287 if (Supports == 0 ||
288 Supports == (EFI_PCI_IO_ATTRIBUTE_ISA_IO |
289 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16)) {
290 Status = EFI_UNSUPPORTED;
291 goto Done;
292 }
293
294 Status = PciIo->Attributes (
295 PciIo,
296 EfiPciIoAttributeOperationGet,
297 0,
298 &OriginalAttributes
299 );
300 if (EFI_ERROR (Status)) {
301 goto Done;
302 }
303
304 Attributes = EFI_PCI_DEVICE_ENABLE |
305 Supports |
306 EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
307 Status = PciIo->Attributes (
308 PciIo,
309 EfiPciIoAttributeOperationEnable,
310 Attributes,
311 NULL
312 );
313 if (EFI_ERROR (Status)) {
314 goto Done;
315 }
316
317 Enabled = TRUE;
318
319 //
320 // Store the OriginalAttributes for the restore in BindingStop()
321 //
322 Private = AllocateZeroPool (sizeof (SIO_BUS_DRIVER_PRIVATE_DATA));
323 if (Private == NULL) {
324 Status = EFI_OUT_OF_RESOURCES;
325 goto Done;
326 }
327 Private->PciIo = PciIo;
328 Private->OriginalAttributes = OriginalAttributes;
329
330 Status = gBS->InstallProtocolInterface (
331 &Controller,
332 &gEfiCallerIdGuid,
333 EFI_NATIVE_INTERFACE,
334 Private
335 );
336 if (EFI_ERROR (Status)) {
337 goto Done;
338 }
339
340 //
341 // Report status code for the start of general controller initialization
342 //
343 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
344 EFI_PROGRESS_CODE,
345 (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
346 ParentDevicePath
347 );
348
349 //
350 // Report status code for the start of enabling devices on the bus
351 //
352 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
353 EFI_PROGRESS_CODE,
354 (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
355 ParentDevicePath
356 );
357
358 //
359 // Create all the children upon the first entrance
360 //
361 ChildDeviceNumber = SioCreateAllChildDevices (
362 This,
363 Controller,
364 PciIo,
365 ParentDevicePath
366 );
367 if (ChildDeviceNumber == 0) {
368 Status = EFI_DEVICE_ERROR;
369 }
370
371 Done:
372 if (EFI_ERROR (Status)) {
373 if (PciIo != NULL && Enabled) {
374 PciIo->Attributes (
375 PciIo,
376 EfiPciIoAttributeOperationSet,
377 OriginalAttributes,
378 NULL
379 );
380 }
381
382 gBS->CloseProtocol (
383 Controller,
384 &gEfiDevicePathProtocolGuid,
385 This->DriverBindingHandle,
386 Controller
387 );
388
389 gBS->CloseProtocol (
390 Controller,
391 &gEfiPciIoProtocolGuid,
392 This->DriverBindingHandle,
393 Controller
394 );
395
396 if (Private != NULL) {
397 gBS->UninstallMultipleProtocolInterfaces (
398 Controller,
399 &gEfiCallerIdGuid,
400 Private,
401 NULL
402 );
403 FreePool (Private);
404 }
405
406 return Status;
407 }
408
409 return EFI_SUCCESS;
410 }
411
412 /**
413 Stops a device controller or a bus controller.
414
415 The Stop() function is designed to be invoked from the EFI boot service
416 DisconnectController(). As a result, much of the error checking on the
417 parameters to Stop() has been moved into this common boot service. It is
418 legal to call Stop() from other locations, but the following calling
419 restrictions must be followed or the system behavior will not be
420 deterministic.
421 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
422 call to this same driver's Start() function.
423 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a
424 valid EFI_HANDLE. In addition, all of these handles must have been created
425 in this driver's Start() function, and the Start() function must have
426 called OpenProtocol() on ControllerHandle with an Attribute of
427 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
428
429 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL
430 instance.
431 @param[in] ControllerHandle A handle to the device being stopped. The
432 handle must support a bus specific I/O
433 protocol for the driver to use to stop the
434 device.
435 @param[in] NumberOfChildren The number of child device handles in
436 ChildHandleBuffer.
437 @param[in] ChildHandleBuffer An array of child handles to be freed. May be
438 NULL if NumberOfChildren is 0.
439
440 @retval EFI_SUCCESS The device was stopped.
441 @retval EFI_DEVICE_ERROR The device could not be stopped due to a
442 device error.
443
444 **/
445 EFI_STATUS
446 EFIAPI
447 SioBusDriverBindingStop (
448 IN EFI_DRIVER_BINDING_PROTOCOL *This,
449 IN EFI_HANDLE Controller,
450 IN UINTN NumberOfChildren,
451 IN EFI_HANDLE *ChildHandleBuffer
452 )
453 {
454 EFI_STATUS Status;
455 SIO_BUS_DRIVER_PRIVATE_DATA *Private;
456 UINTN Index;
457 BOOLEAN AllChildrenStopped;
458 EFI_SIO_PROTOCOL *Sio;
459 SIO_DEV *SioDevice;
460 EFI_PCI_IO_PROTOCOL *PciIo;
461
462 if (NumberOfChildren == 0) {
463 //
464 // Restore PCI attributes
465 //
466 Status = gBS->OpenProtocol (
467 Controller,
468 &gEfiCallerIdGuid,
469 (VOID **) &Private,
470 This->DriverBindingHandle,
471 Controller,
472 EFI_OPEN_PROTOCOL_GET_PROTOCOL
473 );
474 if (EFI_ERROR (Status)) {
475 return Status;
476 }
477
478 Status = Private->PciIo->Attributes (
479 Private->PciIo,
480 EfiPciIoAttributeOperationSet,
481 Private->OriginalAttributes,
482 NULL
483 );
484 if (EFI_ERROR (Status)) {
485 return Status;
486 }
487
488 gBS->UninstallProtocolInterface (
489 Controller,
490 &gEfiCallerIdGuid,
491 Private
492 );
493 FreePool (Private);
494
495 //
496 // Close the bus driver
497 //
498 Status = gBS->CloseProtocol (
499 Controller,
500 &gEfiDevicePathProtocolGuid,
501 This->DriverBindingHandle,
502 Controller
503 );
504 if (EFI_ERROR (Status)) {
505 return Status;
506 }
507
508 Status = gBS->CloseProtocol (
509 Controller,
510 &gEfiPciIoProtocolGuid,
511 This->DriverBindingHandle,
512 Controller
513 );
514 if (EFI_ERROR (Status)) {
515 return Status;
516 }
517
518 return EFI_SUCCESS;
519 }
520
521 //
522 // Stop all the children
523 //
524 AllChildrenStopped = TRUE;
525
526 for (Index = 0; Index < NumberOfChildren; Index++) {
527 Status = gBS->OpenProtocol (
528 ChildHandleBuffer[Index],
529 &gEfiSioProtocolGuid,
530 (VOID **) &Sio,
531 This->DriverBindingHandle,
532 Controller,
533 EFI_OPEN_PROTOCOL_GET_PROTOCOL
534 );
535 if (!EFI_ERROR (Status)) {
536 SioDevice = SIO_DEV_FROM_SIO (Sio);
537
538 //
539 // Close the child handle
540 //
541 Status = gBS->CloseProtocol (
542 Controller,
543 &gEfiPciIoProtocolGuid,
544 This->DriverBindingHandle,
545 ChildHandleBuffer[Index]
546 );
547 Status = gBS->UninstallMultipleProtocolInterfaces (
548 ChildHandleBuffer[Index],
549 &gEfiDevicePathProtocolGuid,
550 SioDevice->DevicePath,
551 &gEfiSioProtocolGuid,
552 &SioDevice->Sio,
553 NULL
554 );
555
556 if (!EFI_ERROR (Status)) {
557 FreePool (SioDevice->DevicePath);
558 FreePool (SioDevice);
559 } else {
560 //
561 // Re-open PCI IO Protocol on behalf of the child device
562 // because of failure of destroying the child device handle
563 //
564 gBS->OpenProtocol (
565 Controller,
566 &gEfiPciIoProtocolGuid,
567 (VOID **) &PciIo,
568 This->DriverBindingHandle,
569 ChildHandleBuffer[Index],
570 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
571 );
572 }
573 }
574
575 if (EFI_ERROR (Status)) {
576 AllChildrenStopped = FALSE;
577 }
578 }
579
580 if (!AllChildrenStopped) {
581 return EFI_DEVICE_ERROR;
582 }
583
584 return EFI_SUCCESS;
585 }
586
587 /**
588 The entry point for the SioBusDxe driver.
589
590 @param[in] ImageHandle The firmware allocated handle for the EFI image.
591 @param[in] SystemTable A pointer to the EFI System Table.
592
593 @retval EFI_SUCCESS The entry point is executed successfully.
594 @retval other Some error occurs when executing this entry point.
595
596 **/
597 EFI_STATUS
598 EFIAPI
599 SioBusDxeDriverEntryPoint (
600 IN EFI_HANDLE ImageHandle,
601 IN EFI_SYSTEM_TABLE *SystemTable
602 )
603 {
604 //
605 // Install driver model protocol(s).
606 //
607 return EfiLibInstallDriverBindingComponentName2 (
608 ImageHandle,
609 SystemTable,
610 &gSioBusDriverBinding,
611 ImageHandle,
612 &gSioBusComponentName,
613 &gSioBusComponentName2
614 );
615 }