1 /****************************************************************************** 2 * 3 * Module Name: exregion - ACPI default OpRegion (address space) handlers 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2021, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpi.h" 45 #include "accommon.h" 46 #include "acinterp.h" 47 48 49 #define _COMPONENT ACPI_EXECUTER 50 ACPI_MODULE_NAME ("exregion") 51 52 53 /******************************************************************************* 54 * 55 * FUNCTION: AcpiExSystemMemorySpaceHandler 56 * 57 * PARAMETERS: Function - Read or Write operation 58 * Address - Where in the space to read or write 59 * BitWidth - Field width in bits (8, 16, or 32) 60 * Value - Pointer to in or out value 61 * HandlerContext - Pointer to Handler's context 62 * RegionContext - Pointer to context specific to the 63 * accessed region 64 * 65 * RETURN: Status 66 * 67 * DESCRIPTION: Handler for the System Memory address space (Op Region) 68 * 69 ******************************************************************************/ 70 71 ACPI_STATUS 72 AcpiExSystemMemorySpaceHandler ( 73 UINT32 Function, 74 ACPI_PHYSICAL_ADDRESS Address, 75 UINT32 BitWidth, 76 UINT64 *Value, 77 void *HandlerContext, 78 void *RegionContext) 79 { 80 ACPI_STATUS Status = AE_OK; 81 void *LogicalAddrPtr = NULL; 82 ACPI_MEM_SPACE_CONTEXT *MemInfo = RegionContext; 83 ACPI_MEM_MAPPING *Mm = MemInfo->CurMm; 84 UINT32 Length; 85 ACPI_SIZE MapLength; 86 ACPI_SIZE PageBoundaryMapLength; 87 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED 88 UINT32 Remainder; 89 #endif 90 91 92 ACPI_FUNCTION_TRACE (ExSystemMemorySpaceHandler); 93 94 95 /* Validate and translate the bit width */ 96 97 switch (BitWidth) 98 { 99 case 8: 100 101 Length = 1; 102 break; 103 104 case 16: 105 106 Length = 2; 107 break; 108 109 case 32: 110 111 Length = 4; 112 break; 113 114 case 64: 115 116 Length = 8; 117 break; 118 119 default: 120 121 ACPI_ERROR ((AE_INFO, "Invalid SystemMemory width %u", 122 BitWidth)); 123 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 124 } 125 126 #ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED 127 /* 128 * Hardware does not support non-aligned data transfers, we must verify 129 * the request. 130 */ 131 (void) AcpiUtShortDivide ((UINT64) Address, Length, NULL, &Remainder); 132 if (Remainder != 0) 133 { 134 return_ACPI_STATUS (AE_AML_ALIGNMENT); 135 } 136 #endif 137 138 /* 139 * Does the request fit into the cached memory mapping? 140 * Is 1) Address below the current mapping? OR 141 * 2) Address beyond the current mapping? 142 */ 143 if (!Mm || (Address < Mm->PhysicalAddress) || 144 ((UINT64) Address + Length > (UINT64) Mm->PhysicalAddress + Mm->Length)) 145 { 146 /* 147 * The request cannot be resolved by the current memory mapping. 148 * 149 * Look for an existing saved mapping covering the address range 150 * at hand. If found, save it as the current one and carry out 151 * the access. 152 */ 153 for (Mm = MemInfo->FirstMm; Mm; Mm = Mm->NextMm) 154 { 155 if (Mm == MemInfo->CurMm) 156 { 157 continue; 158 } 159 160 if (Address < Mm->PhysicalAddress) 161 { 162 continue; 163 } 164 165 if ((UINT64) Address + Length > (UINT64) Mm->PhysicalAddress + Mm->Length) 166 { 167 continue; 168 } 169 170 MemInfo->CurMm = Mm; 171 goto access; 172 } 173 174 /* Create a new mappings list entry */ 175 176 Mm = ACPI_ALLOCATE_ZEROED(sizeof(*Mm)); 177 if (!Mm) 178 { 179 ACPI_ERROR((AE_INFO, 180 "Unable to save memory mapping at 0x%8.8X%8.8X, size %u", 181 ACPI_FORMAT_UINT64(Address), Length)); 182 return_ACPI_STATUS(AE_NO_MEMORY); 183 } 184 185 /* 186 * October 2009: Attempt to map from the requested address to the 187 * end of the region. However, we will never map more than one 188 * page, nor will we cross a page boundary. 189 */ 190 MapLength = (ACPI_SIZE) 191 ((MemInfo->Address + MemInfo->Length) - Address); 192 193 /* 194 * If mapping the entire remaining portion of the region will cross 195 * a page boundary, just map up to the page boundary, do not cross. 196 * On some systems, crossing a page boundary while mapping regions 197 * can cause warnings if the pages have different attributes 198 * due to resource management. 199 * 200 * This has the added benefit of constraining a single mapping to 201 * one page, which is similar to the original code that used a 4k 202 * maximum window. 203 */ 204 PageBoundaryMapLength = (ACPI_SIZE) 205 (ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address); 206 if (PageBoundaryMapLength == 0) 207 { 208 PageBoundaryMapLength = ACPI_DEFAULT_PAGE_SIZE; 209 } 210 211 if (MapLength > PageBoundaryMapLength) 212 { 213 MapLength = PageBoundaryMapLength; 214 } 215 216 /* Create a new mapping starting at the address given */ 217 218 LogicalAddrPtr = AcpiOsMapMemory(Address, MapLength); 219 if (!LogicalAddrPtr) 220 { 221 ACPI_ERROR ((AE_INFO, 222 "Could not map memory at 0x%8.8X%8.8X, size %u", 223 ACPI_FORMAT_UINT64 (Address), (UINT32) MapLength)); 224 ACPI_FREE(Mm); 225 return_ACPI_STATUS (AE_NO_MEMORY); 226 } 227 228 /* Save the physical address and mapping size */ 229 230 Mm->LogicalAddress = LogicalAddrPtr; 231 Mm->PhysicalAddress = Address; 232 Mm->Length = MapLength; 233 234 /* 235 * Add the new entry to the mappigs list and save it as the 236 * current mapping. 237 */ 238 Mm->NextMm = MemInfo->FirstMm; 239 MemInfo->FirstMm = Mm; 240 MemInfo->CurMm = Mm; 241 } 242 243 access: 244 /* 245 * Generate a logical pointer corresponding to the address we want to 246 * access 247 */ 248 LogicalAddrPtr = Mm->LogicalAddress + 249 ((UINT64) Address - (UINT64) Mm->PhysicalAddress); 250 251 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 252 "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n", 253 BitWidth, Function, ACPI_FORMAT_UINT64 (Address))); 254 255 /* 256 * Perform the memory read or write 257 * 258 * Note: For machines that do not support non-aligned transfers, the target 259 * address was checked for alignment above. We do not attempt to break the 260 * transfer up into smaller (byte-size) chunks because the AML specifically 261 * asked for a transfer width that the hardware may require. 262 */ 263 switch (Function) 264 { 265 case ACPI_READ: 266 267 *Value = 0; 268 switch (BitWidth) 269 { 270 case 8: 271 272 *Value = (UINT64) ACPI_GET8 (LogicalAddrPtr); 273 break; 274 275 case 16: 276 277 *Value = (UINT64) ACPI_GET16 (LogicalAddrPtr); 278 break; 279 280 case 32: 281 282 *Value = (UINT64) ACPI_GET32 (LogicalAddrPtr); 283 break; 284 285 case 64: 286 287 *Value = (UINT64) ACPI_GET64 (LogicalAddrPtr); 288 break; 289 290 default: 291 292 /* BitWidth was already validated */ 293 294 break; 295 } 296 break; 297 298 case ACPI_WRITE: 299 300 switch (BitWidth) 301 { 302 case 8: 303 304 ACPI_SET8 (LogicalAddrPtr, *Value); 305 break; 306 307 case 16: 308 309 ACPI_SET16 (LogicalAddrPtr, *Value); 310 break; 311 312 case 32: 313 314 ACPI_SET32 (LogicalAddrPtr, *Value); 315 break; 316 317 case 64: 318 319 ACPI_SET64 (LogicalAddrPtr, *Value); 320 break; 321 322 default: 323 324 /* BitWidth was already validated */ 325 326 break; 327 } 328 break; 329 330 default: 331 332 Status = AE_BAD_PARAMETER; 333 break; 334 } 335 336 return_ACPI_STATUS (Status); 337 } 338 339 340 /******************************************************************************* 341 * 342 * FUNCTION: AcpiExSystemIoSpaceHandler 343 * 344 * PARAMETERS: Function - Read or Write operation 345 * Address - Where in the space to read or write 346 * BitWidth - Field width in bits (8, 16, or 32) 347 * Value - Pointer to in or out value 348 * HandlerContext - Pointer to Handler's context 349 * RegionContext - Pointer to context specific to the 350 * accessed region 351 * 352 * RETURN: Status 353 * 354 * DESCRIPTION: Handler for the System IO address space (Op Region) 355 * 356 ******************************************************************************/ 357 358 ACPI_STATUS 359 AcpiExSystemIoSpaceHandler ( 360 UINT32 Function, 361 ACPI_PHYSICAL_ADDRESS Address, 362 UINT32 BitWidth, 363 UINT64 *Value, 364 void *HandlerContext, 365 void *RegionContext) 366 { 367 ACPI_STATUS Status = AE_OK; 368 UINT32 Value32; 369 370 371 ACPI_FUNCTION_TRACE (ExSystemIoSpaceHandler); 372 373 374 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 375 "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n", 376 BitWidth, Function, ACPI_FORMAT_UINT64 (Address))); 377 378 /* Decode the function parameter */ 379 380 switch (Function) 381 { 382 case ACPI_READ: 383 384 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) Address, 385 &Value32, BitWidth); 386 *Value = Value32; 387 break; 388 389 case ACPI_WRITE: 390 391 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) Address, 392 (UINT32) *Value, BitWidth); 393 break; 394 395 default: 396 397 Status = AE_BAD_PARAMETER; 398 break; 399 } 400 401 return_ACPI_STATUS (Status); 402 } 403 404 405 /******************************************************************************* 406 * 407 * FUNCTION: AcpiExPciConfigSpaceHandler 408 * 409 * PARAMETERS: Function - Read or Write operation 410 * Address - Where in the space to read or write 411 * BitWidth - Field width in bits (8, 16, or 32) 412 * Value - Pointer to in or out value 413 * HandlerContext - Pointer to Handler's context 414 * RegionContext - Pointer to context specific to the 415 * accessed region 416 * 417 * RETURN: Status 418 * 419 * DESCRIPTION: Handler for the PCI Config address space (Op Region) 420 * 421 ******************************************************************************/ 422 423 ACPI_STATUS 424 AcpiExPciConfigSpaceHandler ( 425 UINT32 Function, 426 ACPI_PHYSICAL_ADDRESS Address, 427 UINT32 BitWidth, 428 UINT64 *Value, 429 void *HandlerContext, 430 void *RegionContext) 431 { 432 ACPI_STATUS Status = AE_OK; 433 ACPI_PCI_ID *PciId; 434 UINT16 PciRegister; 435 436 437 ACPI_FUNCTION_TRACE (ExPciConfigSpaceHandler); 438 439 440 /* 441 * The arguments to AcpiOs(Read|Write)PciConfiguration are: 442 * 443 * PciSegment is the PCI bus segment range 0-31 444 * PciBus is the PCI bus number range 0-255 445 * PciDevice is the PCI device number range 0-31 446 * PciFunction is the PCI device function number 447 * PciRegister is the Config space register range 0-255 bytes 448 * 449 * Value - input value for write, output address for read 450 * 451 */ 452 PciId = (ACPI_PCI_ID *) RegionContext; 453 PciRegister = (UINT16) (UINT32) Address; 454 455 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 456 "Pci-Config %u (%u) Seg(%04x) Bus(%04x) " 457 "Dev(%04x) Func(%04x) Reg(%04x)\n", 458 Function, BitWidth, PciId->Segment, PciId->Bus, PciId->Device, 459 PciId->Function, PciRegister)); 460 461 switch (Function) 462 { 463 case ACPI_READ: 464 465 *Value = 0; 466 Status = AcpiOsReadPciConfiguration ( 467 PciId, PciRegister, Value, BitWidth); 468 break; 469 470 case ACPI_WRITE: 471 472 Status = AcpiOsWritePciConfiguration ( 473 PciId, PciRegister, *Value, BitWidth); 474 break; 475 476 default: 477 478 Status = AE_BAD_PARAMETER; 479 break; 480 } 481 482 return_ACPI_STATUS (Status); 483 } 484 485 486 /******************************************************************************* 487 * 488 * FUNCTION: AcpiExCmosSpaceHandler 489 * 490 * PARAMETERS: Function - Read or Write operation 491 * Address - Where in the space to read or write 492 * BitWidth - Field width in bits (8, 16, or 32) 493 * Value - Pointer to in or out value 494 * HandlerContext - Pointer to Handler's context 495 * RegionContext - Pointer to context specific to the 496 * accessed region 497 * 498 * RETURN: Status 499 * 500 * DESCRIPTION: Handler for the CMOS address space (Op Region) 501 * 502 ******************************************************************************/ 503 504 ACPI_STATUS 505 AcpiExCmosSpaceHandler ( 506 UINT32 Function, 507 ACPI_PHYSICAL_ADDRESS Address, 508 UINT32 BitWidth, 509 UINT64 *Value, 510 void *HandlerContext, 511 void *RegionContext) 512 { 513 ACPI_STATUS Status = AE_OK; 514 515 516 ACPI_FUNCTION_TRACE (ExCmosSpaceHandler); 517 518 519 return_ACPI_STATUS (Status); 520 } 521 522 523 /******************************************************************************* 524 * 525 * FUNCTION: AcpiExPciBarSpaceHandler 526 * 527 * PARAMETERS: Function - Read or Write operation 528 * Address - Where in the space to read or write 529 * BitWidth - Field width in bits (8, 16, or 32) 530 * Value - Pointer to in or out value 531 * HandlerContext - Pointer to Handler's context 532 * RegionContext - Pointer to context specific to the 533 * accessed region 534 * 535 * RETURN: Status 536 * 537 * DESCRIPTION: Handler for the PCI BarTarget address space (Op Region) 538 * 539 ******************************************************************************/ 540 541 ACPI_STATUS 542 AcpiExPciBarSpaceHandler ( 543 UINT32 Function, 544 ACPI_PHYSICAL_ADDRESS Address, 545 UINT32 BitWidth, 546 UINT64 *Value, 547 void *HandlerContext, 548 void *RegionContext) 549 { 550 ACPI_STATUS Status = AE_OK; 551 552 553 ACPI_FUNCTION_TRACE (ExPciBarSpaceHandler); 554 555 556 return_ACPI_STATUS (Status); 557 } 558 559 560 /******************************************************************************* 561 * 562 * FUNCTION: AcpiExDataTableSpaceHandler 563 * 564 * PARAMETERS: Function - Read or Write operation 565 * Address - Where in the space to read or write 566 * BitWidth - Field width in bits (8, 16, or 32) 567 * Value - Pointer to in or out value 568 * HandlerContext - Pointer to Handler's context 569 * RegionContext - Pointer to context specific to the 570 * accessed region 571 * 572 * RETURN: Status 573 * 574 * DESCRIPTION: Handler for the Data Table address space (Op Region) 575 * 576 ******************************************************************************/ 577 578 ACPI_STATUS 579 AcpiExDataTableSpaceHandler ( 580 UINT32 Function, 581 ACPI_PHYSICAL_ADDRESS Address, 582 UINT32 BitWidth, 583 UINT64 *Value, 584 void *HandlerContext, 585 void *RegionContext) 586 { 587 ACPI_FUNCTION_TRACE (ExDataTableSpaceHandler); 588 589 590 /* 591 * Perform the memory read or write. The BitWidth was already 592 * validated. 593 */ 594 switch (Function) 595 { 596 case ACPI_READ: 597 598 memcpy (ACPI_CAST_PTR (char, Value), ACPI_PHYSADDR_TO_PTR (Address), 599 ACPI_DIV_8 (BitWidth)); 600 break; 601 602 case ACPI_WRITE: 603 604 memcpy (ACPI_PHYSADDR_TO_PTR (Address), ACPI_CAST_PTR (char, Value), 605 ACPI_DIV_8 (BitWidth)); 606 break; 607 608 default: 609 610 return_ACPI_STATUS (AE_BAD_PARAMETER); 611 } 612 613 return_ACPI_STATUS (AE_OK); 614 } 615