1 /*++ @file
2   Reset Architectural Protocol implementation.
3 
4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 --*/
14 
15 #include <PiDxe.h>
16 
17 #include <Protocol/Reset.h>
18 
19 #include <Guid/AcpiDescription.h>
20 
21 #include <Library/BaseLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/PciLib.h>
24 #include <Library/HobLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 
29 ///
30 /// Handle for the Reset Architectural Protocol
31 ///
32 EFI_HANDLE            mResetHandle = NULL;
33 
34 ///
35 /// Copy of ACPI Description HOB in runtime memory
36 ///
37 EFI_ACPI_DESCRIPTION  mAcpiDescription;
38 
39 /**
40   Reset the system.
41 
42   @param[in] ResetType       Warm or cold
43   @param[in] ResetStatus     Possible cause of reset
44   @param[in] DataSize        Size of ResetData in bytes
45   @param[in] ResetData       Optional Unicode string
46 
47 **/
48 VOID
49 EFIAPI
EfiAcpiResetSystem(IN EFI_RESET_TYPE ResetType,IN EFI_STATUS ResetStatus,IN UINTN DataSize,IN VOID * ResetData OPTIONAL)50 EfiAcpiResetSystem (
51   IN EFI_RESET_TYPE   ResetType,
52   IN EFI_STATUS       ResetStatus,
53   IN UINTN            DataSize,
54   IN VOID             *ResetData OPTIONAL
55   )
56 {
57   UINT8   Dev;
58   UINT8   Func;
59   UINT8   Register;
60 
61   switch (ResetType) {
62   case EfiResetShutdown:
63     //
64     // 1. Write SLP_TYPa
65     //
66     if ((mAcpiDescription.PM1a_CNT_BLK.Address != 0) && (mAcpiDescription.SLP_TYPa != 0)) {
67       switch (mAcpiDescription.PM1a_CNT_BLK.AddressSpaceId) {
68       case EFI_ACPI_3_0_SYSTEM_IO:
69         IoAndThenOr16 ((UINTN)mAcpiDescription.PM1a_CNT_BLK.Address, 0xc3ff, (UINT16)(0x2000 | (mAcpiDescription.SLP_TYPa << 10)));
70         break;
71       case EFI_ACPI_3_0_SYSTEM_MEMORY:
72         MmioAndThenOr16 ((UINTN)mAcpiDescription.PM1a_CNT_BLK.Address, 0xc3ff, (UINT16)(0x2000 | (mAcpiDescription.SLP_TYPa << 10)));
73         break;
74       }
75     }
76 
77     //
78     // 2. Write SLP_TYPb
79     //
80     if ((mAcpiDescription.PM1b_CNT_BLK.Address != 0) && (mAcpiDescription.SLP_TYPb != 0)) {
81       switch (mAcpiDescription.PM1b_CNT_BLK.AddressSpaceId) {
82       case EFI_ACPI_3_0_SYSTEM_IO:
83         IoAndThenOr16 ((UINTN)mAcpiDescription.PM1b_CNT_BLK.Address, 0xc3ff, (UINT16)(0x2000 | (mAcpiDescription.SLP_TYPb << 10)));
84         break;
85       case EFI_ACPI_3_0_SYSTEM_MEMORY:
86         MmioAndThenOr16 ((UINTN)mAcpiDescription.PM1b_CNT_BLK.Address, 0xc3ff, (UINT16)(0x2000 | (mAcpiDescription.SLP_TYPb << 10)));
87         break;
88       }
89     }
90     //
91     // If Shutdown fails, then let fall through to reset
92     //
93   case EfiResetWarm:
94   case EfiResetCold:
95     if ((mAcpiDescription.RESET_REG.Address != 0) &&
96         ((mAcpiDescription.RESET_REG.AddressSpaceId == EFI_ACPI_3_0_SYSTEM_IO) ||
97          (mAcpiDescription.RESET_REG.AddressSpaceId == EFI_ACPI_3_0_SYSTEM_MEMORY) ||
98          (mAcpiDescription.RESET_REG.AddressSpaceId == EFI_ACPI_3_0_PCI_CONFIGURATION_SPACE))) {
99       //
100       // Use ACPI System Reset
101       //
102       switch (mAcpiDescription.RESET_REG.AddressSpaceId) {
103       case EFI_ACPI_3_0_SYSTEM_IO:
104         //
105         // Send reset request through I/O port register
106         //
107         IoWrite8 ((UINTN)mAcpiDescription.RESET_REG.Address, mAcpiDescription.RESET_VALUE);
108         //
109         // Halt
110         //
111         CpuDeadLoop ();
112       case EFI_ACPI_3_0_SYSTEM_MEMORY:
113         //
114         // Send reset request through MMIO register
115         //
116         MmioWrite8 ((UINTN)mAcpiDescription.RESET_REG.Address, mAcpiDescription.RESET_VALUE);
117         //
118         // Halt
119         //
120         CpuDeadLoop ();
121       case EFI_ACPI_3_0_PCI_CONFIGURATION_SPACE:
122         //
123         // Send reset request through PCI register
124         //
125         Register = (UINT8)mAcpiDescription.RESET_REG.Address;
126         Func     = (UINT8) (RShiftU64 (mAcpiDescription.RESET_REG.Address, 16) & 0x7);
127         Dev      = (UINT8) (RShiftU64 (mAcpiDescription.RESET_REG.Address, 32) & 0x1F);
128         PciWrite8 (PCI_LIB_ADDRESS (0, Dev, Func, Register), mAcpiDescription.RESET_VALUE);
129         //
130         // Halt
131         //
132         CpuDeadLoop ();
133       }
134     }
135 
136     //
137     // If system comes here, means ACPI reset is not supported, so do Legacy System Reset, assume 8042 available
138     //
139     IoWrite8 (0x64, 0xfe);
140     CpuDeadLoop ();
141 
142   default:
143     break;
144   }
145 
146   //
147   // Given we should have reset getting here would be bad
148   //
149   ASSERT (FALSE);
150   CpuDeadLoop();
151 }
152 
153 /**
154   Initialize the state information for the Reset Architectural Protocol.
155 
156   @param[in] ImageHandle  Image handle of the loaded driver
157   @param[in] SystemTable  Pointer to the System Table
158 
159   @retval EFI_SUCCESS           Thread can be successfully created
160   @retval EFI_UNSUPPORTED       Cannot find the info to reset system
161 
162 **/
163 EFI_STATUS
164 EFIAPI
InitializeReset(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)165 InitializeReset (
166   IN EFI_HANDLE        ImageHandle,
167   IN EFI_SYSTEM_TABLE  *SystemTable
168   )
169 {
170   EFI_STATUS         Status;
171   EFI_HOB_GUID_TYPE  *HobAcpiDescription;
172 
173   //
174   // Make sure the Reset Architectural Protocol is not already installed in the system
175   //
176   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiResetArchProtocolGuid);
177 
178   //
179   // Get ACPI Description HOB
180   //
181   HobAcpiDescription = GetFirstGuidHob (&gEfiAcpiDescriptionGuid);
182   if (HobAcpiDescription == NULL) {
183     return EFI_UNSUPPORTED;
184   }
185 
186   //
187   // Copy it to Runtime Memory
188   //
189   ASSERT (sizeof (EFI_ACPI_DESCRIPTION) == GET_GUID_HOB_DATA_SIZE (HobAcpiDescription));
190   CopyMem (&mAcpiDescription, GET_GUID_HOB_DATA (HobAcpiDescription), sizeof (EFI_ACPI_DESCRIPTION));
191 
192   DEBUG ((DEBUG_INFO, "ACPI Reset Base  - %lx\n", mAcpiDescription.RESET_REG.Address));
193   DEBUG ((DEBUG_INFO, "ACPI Reset Value - %02x\n", (UINTN)mAcpiDescription.RESET_VALUE));
194   DEBUG ((DEBUG_INFO, "IAPC support     - %x\n", (UINTN)(mAcpiDescription.IAPC_BOOT_ARCH)));
195 
196   //
197   // Hook the runtime service table
198   //
199   SystemTable->RuntimeServices->ResetSystem = EfiAcpiResetSystem;
200 
201   //
202   // Install the Reset Architectural Protocol onto a new handle
203   //
204   Status = gBS->InstallMultipleProtocolInterfaces (
205                   &mResetHandle,
206                   &gEfiResetArchProtocolGuid, NULL,
207                   NULL
208                   );
209   ASSERT_EFI_ERROR (Status);
210 
211   return Status;
212 }
213