1 /*++
2 
3 Copyright (c)  1999  - 2014, Intel Corporation. All rights reserved
4 
5 
6   This program and the accompanying materials are licensed and made available under
7 
8   the terms and conditions of the BSD License that accompanies this distribution.
9 
10   The full text of the license may be found at
11 
12   http://opensource.org/licenses/bsd-license.php.
13 
14 
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 
21 
22 
23 
24 Module Name:
25 
26   EfiRegTableLib.c
27 
28 Abstract:
29 
30   Lib function for table driven register initialization.
31 
32 Revision History
33 
34 --*/
35 
36 #include <Library/EfiRegTableLib.h>
37 #include <Library/S3BootScriptLib.h>
38 
39 //
40 // Local Functions
41 //
42 
43 /**
44   Local worker function to process PCI_WRITE table entries.  Performs write and
45   may also call BootScriptSave protocol if indicated in the Entry flags
46 
47   @param Entry            A pointer to the PCI_WRITE entry to process
PciWrite(EFI_REG_TABLE_PCI_WRITE * Entry,EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo)48 
49   @param PciRootBridgeIo  A pointer to the instance of PciRootBridgeIo that is used
50                           when processing the entry.
51 
52   @retval Nothing.
53 
54 **/
55 STATIC
56 VOID
57 PciWrite (
58   EFI_REG_TABLE_PCI_WRITE             *Entry,
59   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo
60   )
61 {
62   EFI_STATUS  Status;
63 
64   Status = PciRootBridgeIo->Pci.Write (
65                                   PciRootBridgeIo,
66                                   (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
67                                   (UINT64) Entry->PciAddress,
68                                   1,
69                                   &Entry->Data
70                                   );
71   ASSERT_EFI_ERROR (Status);
72 
73   if (OPCODE_FLAGS (Entry->OpCode) & OPCODE_FLAG_S3SAVE) {
74     Status = S3BootScriptSavePciCfgWrite (
75               (EFI_BOOT_SCRIPT_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
76               (UINT64) Entry->PciAddress,
77               1,
78               &Entry->Data
79               );
80     ASSERT_EFI_ERROR (Status);
81   }
82 }
83 
84 /**
85   Local worker function to process PCI_READ_MODIFY_WRITE table entries.
86   Performs RMW write and may also call BootScriptSave protocol if indicated in
87   the Entry flags.
88 
89   @param Entry            A pointer to the PCI_READ_MODIFY_WRITE entry to process.
PciReadModifyWrite(EFI_REG_TABLE_PCI_READ_MODIFY_WRITE * Entry,EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo)90 
91   @param PciRootBridgeIo  A pointer to the instance of PciRootBridgeIo that is used
92                           when processing the entry.
93 
94   @retval Nothing.
95 
96 **/
97 STATIC
98 VOID
99 PciReadModifyWrite (
100   EFI_REG_TABLE_PCI_READ_MODIFY_WRITE *Entry,
101   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo
102   )
103 {
104   EFI_STATUS  Status;
105   UINT32      TempData;
106 
107   Status = PciRootBridgeIo->Pci.Read (
108                                   PciRootBridgeIo,
109                                   (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
110                                   (UINT64) Entry->PciAddress,
111                                   1,
112                                   &TempData
113                                   );
114   ASSERT_EFI_ERROR (Status);
115 
116   Entry->OrMask &= Entry->AndMask;
117   TempData &= ~Entry->AndMask;
118   TempData |= Entry->OrMask;
119 
120   Status = PciRootBridgeIo->Pci.Write (
121                                   PciRootBridgeIo,
122                                   (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
123                                   (UINT64) Entry->PciAddress,
124                                   1,
125                                   &TempData
126                                   );
127   ASSERT_EFI_ERROR (Status);
128 
129   if (OPCODE_FLAGS (Entry->OpCode) & OPCODE_FLAG_S3SAVE) {
130     Status = S3BootScriptSavePciCfgReadWrite (
131               (EFI_BOOT_SCRIPT_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
132               (UINT64) Entry->PciAddress,
133               &Entry->OrMask,
134               &Entry->AndMask
135               );
136     ASSERT_EFI_ERROR (Status);
137   }
138 }
139 
140 /**
141   Local worker function to process MEM_READ_MODIFY_WRITE table entries.
142   Performs RMW write and may also call BootScriptSave protocol if indicated in
143   the Entry flags.
144 
145   @param Entry            A pointer to the MEM_READ_MODIFY_WRITE entry to process.
MemReadModifyWrite(EFI_REG_TABLE_MEM_READ_MODIFY_WRITE * Entry,EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo)146 
147   @param PciRootBridgeIo  A pointer to the instance of PciRootBridgeIo that is used
148                           when processing the entry.
149 
150   @retval Nothing.
151 
152 **/
153 STATIC
154 VOID
155 MemReadModifyWrite (
156   EFI_REG_TABLE_MEM_READ_MODIFY_WRITE *Entry,
157   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo
158   )
159 {
160   EFI_STATUS  Status;
161   UINT32      TempData;
162 
163   Status = PciRootBridgeIo->Mem.Read (
164                                   PciRootBridgeIo,
165                                   (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
166                                   (UINT64) Entry->MemAddress,
167                                   1,
168                                   &TempData
169                                   );
170   ASSERT_EFI_ERROR (Status);
171 
172   Entry->OrMask &= Entry->AndMask;
173   TempData &= ~Entry->AndMask;
174   TempData |= Entry->OrMask;
175 
176   Status = PciRootBridgeIo->Mem.Write (
177                                   PciRootBridgeIo,
178                                   (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
179                                   (UINT64) Entry->MemAddress,
180                                   1,
181                                   &TempData
182                                   );
183   ASSERT_EFI_ERROR (Status);
184 
185   if (OPCODE_FLAGS (Entry->OpCode) & OPCODE_FLAG_S3SAVE) {
186     Status = S3BootScriptSaveMemReadWrite (
187               (EFI_BOOT_SCRIPT_WIDTH) (OPCODE_EXTRA_DATA (Entry->OpCode)),
188               Entry->MemAddress,
189               &Entry->OrMask,
190               &Entry->AndMask
191               );
192     ASSERT_EFI_ERROR (Status);
193   }
194 }
195 
196 //
197 // Exported functions
198 //
199 
200 /**
201   Processes register table assuming which may contain PCI, IO, MEM, and STALL
202   entries.
203 
204   No parameter checking is done so the caller must be careful about omitting
205   values for PciRootBridgeIo or CpuIo parameters.  If the regtable does
206   not contain any PCI accesses, it is safe to omit the PciRootBridgeIo (supply
207   NULL).  If the regtable does not contain any IO or Mem entries, it is safe to
208   omit the CpuIo (supply NULL).
209 
210   The RegTableEntry parameter is not checked, but is required.
211 
212   gBS is assumed to have been defined and is used when processing stalls.
213 
214   The function processes each entry sequentially until an OP_TERMINATE_TABLE
215   entry is encountered.
216 
217   @param RegTableEntry    A pointer to the register table to process
218 
219   @param PciRootBridgeIo  A pointer to the instance of PciRootBridgeIo that is used
ProcessRegTablePci(EFI_REG_TABLE * RegTableEntry,EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * PciRootBridgeIo,EFI_CPU_IO_PROTOCOL * CpuIo)220                           when processing PCI table entries
221 
222   @param CpuIo            A pointer to the instance of CpuIo that is used when processing IO and
223                           MEM table entries
224 
225   @retval Nothing.
226 
227 **/
228 VOID
229 ProcessRegTablePci (
230   EFI_REG_TABLE                       *RegTableEntry,
231   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL     *PciRootBridgeIo,
232   EFI_CPU_IO_PROTOCOL                 *CpuIo
233   )
234 {
235   while (OPCODE_BASE (RegTableEntry->Generic.OpCode) != OP_TERMINATE_TABLE) {
236     switch (OPCODE_BASE (RegTableEntry->Generic.OpCode)) {
237     case OP_PCI_WRITE:
238       PciWrite ((EFI_REG_TABLE_PCI_WRITE *) RegTableEntry, PciRootBridgeIo);
239       break;
240 
241     case OP_PCI_READ_MODIFY_WRITE:
242       PciReadModifyWrite ((EFI_REG_TABLE_PCI_READ_MODIFY_WRITE *) RegTableEntry, PciRootBridgeIo);
243       break;
244 
245     case OP_MEM_READ_MODIFY_WRITE:
246       MemReadModifyWrite ((EFI_REG_TABLE_MEM_READ_MODIFY_WRITE *) RegTableEntry, PciRootBridgeIo);
247       break;
248 
249     default:
250       DEBUG ((EFI_D_ERROR, "RegTable ERROR: Unknown RegTable OpCode (%x)\n", OPCODE_BASE (RegTableEntry->Generic.OpCode)));
251       ASSERT (0);
252       break;
253     }
254 
255     RegTableEntry++;
256   }
257 }
258 
259 /**
260   Processes register table assuming which may contain IO, MEM, and STALL
261   entries, but must NOT contain any PCI entries.  Any PCI entries cause an
262   ASSERT in a DEBUG build and are skipped in a free build.
263 
264   No parameter checking is done.  Both RegTableEntry and CpuIo parameters are
265   required.
266 
267   gBS is assumed to have been defined and is used when processing stalls.
268 
269   The function processes each entry sequentially until an OP_TERMINATE_TABLE
270   entry is encountered.
271 
ProcessRegTableCpu(EFI_REG_TABLE * RegTableEntry,EFI_CPU_IO_PROTOCOL * CpuIo)272   @param  RegTableEntry   A pointer to the register table to process
273 
274   @param  CpuIo           A pointer to the instance of CpuIo that is used when processing IO and
275                           MEM table entries
276 
277   @retval Nothing.
278 
279 **/
280 VOID
281 ProcessRegTableCpu (
282   EFI_REG_TABLE                       *RegTableEntry,
283   EFI_CPU_IO_PROTOCOL                 *CpuIo
284   )
285 {
286   while (OPCODE_BASE (RegTableEntry->Generic.OpCode) != OP_TERMINATE_TABLE) {
287     switch (OPCODE_BASE (RegTableEntry->Generic.OpCode)) {
288     default:
289       DEBUG ((EFI_D_ERROR, "RegTable ERROR: Unknown RegTable OpCode (%x)\n", OPCODE_BASE (RegTableEntry->Generic.OpCode)));
290       ASSERT (0);
291       break;
292     }
293 
294     RegTableEntry++;
295   }
296 }
297