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