Path: blob/main/sys/contrib/dev/acpica/components/executer/exfldio.c
48521 views
/******************************************************************************1*2* Module Name: exfldio - Aml Field I/O3*4*****************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151#include <contrib/dev/acpica/include/acpi.h>152#include <contrib/dev/acpica/include/accommon.h>153#include <contrib/dev/acpica/include/acinterp.h>154#include <contrib/dev/acpica/include/amlcode.h>155#include <contrib/dev/acpica/include/acevents.h>156#include <contrib/dev/acpica/include/acdispat.h>157158159#define _COMPONENT ACPI_EXECUTER160ACPI_MODULE_NAME ("exfldio")161162/* Local prototypes */163164static ACPI_STATUS165AcpiExFieldDatumIo (166ACPI_OPERAND_OBJECT *ObjDesc,167UINT32 FieldDatumByteOffset,168UINT64 *Value,169UINT32 ReadWrite);170171static BOOLEAN172AcpiExRegisterOverflow (173ACPI_OPERAND_OBJECT *ObjDesc,174UINT64 Value);175176static ACPI_STATUS177AcpiExSetupRegion (178ACPI_OPERAND_OBJECT *ObjDesc,179UINT32 FieldDatumByteOffset);180181182/*******************************************************************************183*184* FUNCTION: AcpiExSetupRegion185*186* PARAMETERS: ObjDesc - Field to be read or written187* FieldDatumByteOffset - Byte offset of this datum within the188* parent field189*190* RETURN: Status191*192* DESCRIPTION: Common processing for AcpiExExtractFromField and193* AcpiExInsertIntoField. Initialize the Region if necessary and194* validate the request.195*196******************************************************************************/197198static ACPI_STATUS199AcpiExSetupRegion (200ACPI_OPERAND_OBJECT *ObjDesc,201UINT32 FieldDatumByteOffset)202{203ACPI_STATUS Status = AE_OK;204ACPI_OPERAND_OBJECT *RgnDesc;205UINT8 SpaceId;206207208ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);209210211RgnDesc = ObjDesc->CommonField.RegionObj;212213/* We must have a valid region */214215if (RgnDesc->Common.Type != ACPI_TYPE_REGION)216{217ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",218RgnDesc->Common.Type,219AcpiUtGetObjectTypeName (RgnDesc)));220221return_ACPI_STATUS (AE_AML_OPERAND_TYPE);222}223224SpaceId = RgnDesc->Region.SpaceId;225226/* Validate the Space ID */227228if (!AcpiIsValidSpaceId (SpaceId))229{230ACPI_ERROR ((AE_INFO,231"Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));232return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);233}234235/*236* If the Region Address and Length have not been previously evaluated,237* evaluate them now and save the results.238*/239if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))240{241Status = AcpiDsGetRegionArguments (RgnDesc);242if (ACPI_FAILURE (Status))243{244return_ACPI_STATUS (Status);245}246}247248/*249* Exit now for SMBus, GSBus or IPMI address space, it has a non-linear250* address space and the request cannot be directly validated251*/252if (SpaceId == ACPI_ADR_SPACE_SMBUS ||253SpaceId == ACPI_ADR_SPACE_GSBUS ||254SpaceId == ACPI_ADR_SPACE_IPMI)255{256/* SMBus or IPMI has a non-linear address space */257258return_ACPI_STATUS (AE_OK);259}260261#ifdef ACPI_UNDER_DEVELOPMENT262/*263* If the Field access is AnyAcc, we can now compute the optimal264* access (because we know the length of the parent region)265*/266if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))267{268if (ACPI_FAILURE (Status))269{270return_ACPI_STATUS (Status);271}272}273#endif274275/*276* Validate the request. The entire request from the byte offset for a277* length of one field datum (access width) must fit within the region.278* (Region length is specified in bytes)279*/280if (RgnDesc->Region.Length <281(ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +282ObjDesc->CommonField.AccessByteWidth))283{284if (AcpiGbl_EnableInterpreterSlack)285{286/*287* Slack mode only: We will go ahead and allow access to this288* field if it is within the region length rounded up to the next289* access width boundary. ACPI_SIZE cast for 64-bit compile.290*/291if (ACPI_ROUND_UP (RgnDesc->Region.Length,292ObjDesc->CommonField.AccessByteWidth) >=293((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +294ObjDesc->CommonField.AccessByteWidth +295FieldDatumByteOffset))296{297return_ACPI_STATUS (AE_OK);298}299}300301if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)302{303/*304* This is the case where the AccessType (AccWord, etc.) is wider305* than the region itself. For example, a region of length one306* byte, and a field with Dword access specified.307*/308ACPI_ERROR ((AE_INFO,309"Field [%4.4s] access width (%u bytes) "310"too large for region [%4.4s] (length %u)",311AcpiUtGetNodeName (ObjDesc->CommonField.Node),312ObjDesc->CommonField.AccessByteWidth,313AcpiUtGetNodeName (RgnDesc->Region.Node),314RgnDesc->Region.Length));315}316317/*318* Offset rounded up to next multiple of field width319* exceeds region length, indicate an error320*/321ACPI_ERROR ((AE_INFO,322"Field [%4.4s] Base+Offset+Width %u+%u+%u "323"is beyond end of region [%4.4s] (length %u)",324AcpiUtGetNodeName (ObjDesc->CommonField.Node),325ObjDesc->CommonField.BaseByteOffset,326FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,327AcpiUtGetNodeName (RgnDesc->Region.Node),328RgnDesc->Region.Length));329330return_ACPI_STATUS (AE_AML_REGION_LIMIT);331}332333return_ACPI_STATUS (AE_OK);334}335336337/*******************************************************************************338*339* FUNCTION: AcpiExAccessRegion340*341* PARAMETERS: ObjDesc - Field to be read342* FieldDatumByteOffset - Byte offset of this datum within the343* parent field344* Value - Where to store value (must at least345* 64 bits)346* Function - Read or Write flag plus other region-347* dependent flags348*349* RETURN: Status350*351* DESCRIPTION: Read or Write a single field datum to an Operation Region.352*353******************************************************************************/354355ACPI_STATUS356AcpiExAccessRegion (357ACPI_OPERAND_OBJECT *ObjDesc,358UINT32 FieldDatumByteOffset,359UINT64 *Value,360UINT32 Function)361{362ACPI_STATUS Status;363ACPI_OPERAND_OBJECT *RgnDesc;364UINT32 RegionOffset;365366367ACPI_FUNCTION_TRACE (ExAccessRegion);368369370/*371* Ensure that the region operands are fully evaluated and verify372* the validity of the request373*/374Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);375if (ACPI_FAILURE (Status))376{377return_ACPI_STATUS (Status);378}379380/*381* The physical address of this field datum is:382*383* 1) The base of the region, plus384* 2) The base offset of the field, plus385* 3) The current offset into the field386*/387RgnDesc = ObjDesc->CommonField.RegionObj;388RegionOffset =389ObjDesc->CommonField.BaseByteOffset +390FieldDatumByteOffset;391392if ((Function & ACPI_IO_MASK) == ACPI_READ)393{394ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));395}396else397{398ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));399}400401ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,402" Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",403AcpiUtGetRegionName (RgnDesc->Region.SpaceId),404RgnDesc->Region.SpaceId,405ObjDesc->CommonField.AccessByteWidth,406ObjDesc->CommonField.BaseByteOffset,407FieldDatumByteOffset,408ACPI_FORMAT_UINT64 (RgnDesc->Region.Address + RegionOffset)));409410/* Invoke the appropriate AddressSpace/OpRegion handler */411412Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc,413Function, RegionOffset,414ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);415416if (ACPI_FAILURE (Status))417{418if (Status == AE_NOT_IMPLEMENTED)419{420ACPI_ERROR ((AE_INFO,421"Region %s (ID=%u) not implemented",422AcpiUtGetRegionName (RgnDesc->Region.SpaceId),423RgnDesc->Region.SpaceId));424}425else if (Status == AE_NOT_EXIST)426{427ACPI_ERROR ((AE_INFO,428"Region %s (ID=%u) has no handler",429AcpiUtGetRegionName (RgnDesc->Region.SpaceId),430RgnDesc->Region.SpaceId));431}432}433434return_ACPI_STATUS (Status);435}436437438/*******************************************************************************439*440* FUNCTION: AcpiExRegisterOverflow441*442* PARAMETERS: ObjDesc - Register(Field) to be written443* Value - Value to be stored444*445* RETURN: TRUE if value overflows the field, FALSE otherwise446*447* DESCRIPTION: Check if a value is out of range of the field being written.448* Used to check if the values written to Index and Bank registers449* are out of range. Normally, the value is simply truncated450* to fit the field, but this case is most likely a serious451* coding error in the ASL.452*453******************************************************************************/454455static BOOLEAN456AcpiExRegisterOverflow (457ACPI_OPERAND_OBJECT *ObjDesc,458UINT64 Value)459{460461if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)462{463/*464* The field is large enough to hold the maximum integer, so we can465* never overflow it.466*/467return (FALSE);468}469470if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))471{472/*473* The Value is larger than the maximum value that can fit into474* the register.475*/476ACPI_ERROR ((AE_INFO,477"Index value 0x%8.8X%8.8X overflows field width 0x%X",478ACPI_FORMAT_UINT64 (Value),479ObjDesc->CommonField.BitLength));480481return (TRUE);482}483484/* The Value will fit into the field with no truncation */485486return (FALSE);487}488489490/*******************************************************************************491*492* FUNCTION: AcpiExFieldDatumIo493*494* PARAMETERS: ObjDesc - Field to be read495* FieldDatumByteOffset - Byte offset of this datum within the496* parent field497* Value - Where to store value (must be 64 bits)498* ReadWrite - Read or Write flag499*500* RETURN: Status501*502* DESCRIPTION: Read or Write a single datum of a field. The FieldType is503* demultiplexed here to handle the different types of fields504* (BufferField, RegionField, IndexField, BankField)505*506******************************************************************************/507508static ACPI_STATUS509AcpiExFieldDatumIo (510ACPI_OPERAND_OBJECT *ObjDesc,511UINT32 FieldDatumByteOffset,512UINT64 *Value,513UINT32 ReadWrite)514{515ACPI_STATUS Status;516UINT64 LocalValue;517518519ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);520521522if (ReadWrite == ACPI_READ)523{524if (!Value)525{526LocalValue = 0;527528/* To support reads without saving return value */529Value = &LocalValue;530}531532/* Clear the entire return buffer first, [Very Important!] */533534*Value = 0;535}536537/*538* The four types of fields are:539*540* BufferField - Read/write from/to a Buffer541* RegionField - Read/write from/to a Operation Region.542* BankField - Write to a Bank Register, then read/write from/to an543* OperationRegion544* IndexField - Write to an Index Register, then read/write from/to a545* Data Register546*/547switch (ObjDesc->Common.Type)548{549case ACPI_TYPE_BUFFER_FIELD:550/*551* If the BufferField arguments have not been previously evaluated,552* evaluate them now and save the results.553*/554if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))555{556Status = AcpiDsGetBufferFieldArguments (ObjDesc);557if (ACPI_FAILURE (Status))558{559return_ACPI_STATUS (Status);560}561}562563if (ReadWrite == ACPI_READ)564{565/*566* Copy the data from the source buffer.567* Length is the field width in bytes.568*/569memcpy (Value,570(ObjDesc->BufferField.BufferObj)->Buffer.Pointer +571ObjDesc->BufferField.BaseByteOffset +572FieldDatumByteOffset,573ObjDesc->CommonField.AccessByteWidth);574}575else576{577/*578* Copy the data to the target buffer.579* Length is the field width in bytes.580*/581memcpy ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +582ObjDesc->BufferField.BaseByteOffset +583FieldDatumByteOffset,584Value, ObjDesc->CommonField.AccessByteWidth);585}586587Status = AE_OK;588break;589590case ACPI_TYPE_LOCAL_BANK_FIELD:591/*592* Ensure that the BankValue is not beyond the capacity of593* the register594*/595if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,596(UINT64) ObjDesc->BankField.Value))597{598return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);599}600601/*602* For BankFields, we must write the BankValue to the BankRegister603* (itself a RegionField) before we can access the data.604*/605Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,606&ObjDesc->BankField.Value,607sizeof (ObjDesc->BankField.Value));608if (ACPI_FAILURE (Status))609{610return_ACPI_STATUS (Status);611}612613/*614* Now that the Bank has been selected, fall through to the615* RegionField case and write the datum to the Operation Region616*/617618ACPI_FALLTHROUGH;619620case ACPI_TYPE_LOCAL_REGION_FIELD:621/*622* For simple RegionFields, we just directly access the owning623* Operation Region.624*/625Status = AcpiExAccessRegion (626ObjDesc, FieldDatumByteOffset, Value, ReadWrite);627break;628629case ACPI_TYPE_LOCAL_INDEX_FIELD:630/*631* Ensure that the IndexValue is not beyond the capacity of632* the register633*/634if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,635(UINT64) ObjDesc->IndexField.Value))636{637return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);638}639640/* Write the index value to the IndexRegister (itself a RegionField) */641642FieldDatumByteOffset += ObjDesc->IndexField.Value;643644ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,645"Write to Index Register: Value %8.8X\n",646FieldDatumByteOffset));647648Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,649&FieldDatumByteOffset, sizeof (FieldDatumByteOffset));650if (ACPI_FAILURE (Status))651{652return_ACPI_STATUS (Status);653}654655if (ReadWrite == ACPI_READ)656{657/* Read the datum from the DataRegister */658659ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,660"Read from Data Register\n"));661662Status = AcpiExExtractFromField (663ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));664}665else666{667/* Write the datum to the DataRegister */668669ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,670"Write to Data Register: Value %8.8X%8.8X\n",671ACPI_FORMAT_UINT64 (*Value)));672673Status = AcpiExInsertIntoField (674ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));675}676break;677678default:679680ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",681ObjDesc->Common.Type));682Status = AE_AML_INTERNAL;683break;684}685686if (ACPI_SUCCESS (Status))687{688if (ReadWrite == ACPI_READ)689{690ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,691"Value Read %8.8X%8.8X, Width %u\n",692ACPI_FORMAT_UINT64 (*Value),693ObjDesc->CommonField.AccessByteWidth));694}695else696{697ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,698"Value Written %8.8X%8.8X, Width %u\n",699ACPI_FORMAT_UINT64 (*Value),700ObjDesc->CommonField.AccessByteWidth));701}702}703704return_ACPI_STATUS (Status);705}706707708/*******************************************************************************709*710* FUNCTION: AcpiExWriteWithUpdateRule711*712* PARAMETERS: ObjDesc - Field to be written713* Mask - bitmask within field datum714* FieldValue - Value to write715* FieldDatumByteOffset - Offset of datum within field716*717* RETURN: Status718*719* DESCRIPTION: Apply the field update rule to a field write720*721******************************************************************************/722723ACPI_STATUS724AcpiExWriteWithUpdateRule (725ACPI_OPERAND_OBJECT *ObjDesc,726UINT64 Mask,727UINT64 FieldValue,728UINT32 FieldDatumByteOffset)729{730ACPI_STATUS Status = AE_OK;731UINT64 MergedValue;732UINT64 CurrentValue;733734735ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);736737738/* Start with the new bits */739740MergedValue = FieldValue;741742/* If the mask is all ones, we don't need to worry about the update rule */743744if (Mask != ACPI_UINT64_MAX)745{746/* Decode the update rule */747748switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)749{750case AML_FIELD_UPDATE_PRESERVE:751/*752* Check if update rule needs to be applied (not if mask is all753* ones) The left shift drops the bits we want to ignore.754*/755if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -756ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)757{758/*759* Read the current contents of the byte/word/dword containing760* the field, and merge with the new field value.761*/762Status = AcpiExFieldDatumIo (763ObjDesc, FieldDatumByteOffset, &CurrentValue, ACPI_READ);764if (ACPI_FAILURE (Status))765{766return_ACPI_STATUS (Status);767}768769MergedValue |= (CurrentValue & ~Mask);770}771break;772773case AML_FIELD_UPDATE_WRITE_AS_ONES:774775/* Set positions outside the field to all ones */776777MergedValue |= ~Mask;778break;779780case AML_FIELD_UPDATE_WRITE_AS_ZEROS:781782/* Set positions outside the field to all zeros */783784MergedValue &= Mask;785break;786787default:788789ACPI_ERROR ((AE_INFO,790"Unknown UpdateRule value: 0x%X",791(ObjDesc->CommonField.FieldFlags &792AML_FIELD_UPDATE_RULE_MASK)));793return_ACPI_STATUS (AE_AML_OPERAND_VALUE);794}795}796797ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,798"Mask %8.8X%8.8X, DatumOffset %X, Width %X, "799"Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",800ACPI_FORMAT_UINT64 (Mask),801FieldDatumByteOffset,802ObjDesc->CommonField.AccessByteWidth,803ACPI_FORMAT_UINT64 (FieldValue),804ACPI_FORMAT_UINT64 (MergedValue)));805806/* Write the merged value */807808Status = AcpiExFieldDatumIo (809ObjDesc, FieldDatumByteOffset, &MergedValue, ACPI_WRITE);810811return_ACPI_STATUS (Status);812}813814815/*******************************************************************************816*817* FUNCTION: AcpiExExtractFromField818*819* PARAMETERS: ObjDesc - Field to be read820* Buffer - Where to store the field data821* BufferLength - Length of Buffer822*823* RETURN: Status824*825* DESCRIPTION: Retrieve the current value of the given field826*827******************************************************************************/828829ACPI_STATUS830AcpiExExtractFromField (831ACPI_OPERAND_OBJECT *ObjDesc,832void *Buffer,833UINT32 BufferLength)834{835ACPI_STATUS Status;836UINT64 RawDatum;837UINT64 MergedDatum;838UINT32 FieldOffset = 0;839UINT32 BufferOffset = 0;840UINT32 BufferTailBits;841UINT32 DatumCount;842UINT32 FieldDatumCount;843UINT32 AccessBitWidth;844UINT32 i;845846847ACPI_FUNCTION_TRACE (ExExtractFromField);848849850/* Validate target buffer and clear it */851852if (BufferLength <853ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))854{855ACPI_ERROR ((AE_INFO,856"Field size %u (bits) is too large for buffer (%u)",857ObjDesc->CommonField.BitLength, BufferLength));858859return_ACPI_STATUS (AE_BUFFER_OVERFLOW);860}861862memset (Buffer, 0, BufferLength);863AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);864865/* Handle the simple case here */866867if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&868(ObjDesc->CommonField.BitLength == AccessBitWidth))869{870if (BufferLength >= sizeof (UINT64))871{872Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);873}874else875{876/* Use RawDatum (UINT64) to handle buffers < 64 bits */877878Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ);879memcpy (Buffer, &RawDatum, BufferLength);880}881882return_ACPI_STATUS (Status);883}884885/* TBD: Move to common setup code */886887/* Field algorithm is limited to sizeof(UINT64), truncate if needed */888889if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))890{891ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);892AccessBitWidth = sizeof (UINT64) * 8;893}894895/* Compute the number of datums (access width data items) */896897DatumCount = ACPI_ROUND_UP_TO (898ObjDesc->CommonField.BitLength, AccessBitWidth);899900FieldDatumCount = ACPI_ROUND_UP_TO (901ObjDesc->CommonField.BitLength +902ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);903904/* Priming read from the field */905906Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);907if (ACPI_FAILURE (Status))908{909return_ACPI_STATUS (Status);910}911MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;912913/* Read the rest of the field */914915for (i = 1; i < FieldDatumCount; i++)916{917/* Get next input datum from the field */918919FieldOffset += ObjDesc->CommonField.AccessByteWidth;920Status = AcpiExFieldDatumIo (921ObjDesc, FieldOffset, &RawDatum, ACPI_READ);922if (ACPI_FAILURE (Status))923{924return_ACPI_STATUS (Status);925}926927/*928* Merge with previous datum if necessary.929*930* Note: Before the shift, check if the shift value will be larger than931* the integer size. If so, there is no need to perform the operation.932* This avoids the differences in behavior between different compilers933* concerning shift values larger than the target data width.934*/935if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <936ACPI_INTEGER_BIT_SIZE)937{938MergedDatum |= RawDatum <<939(AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);940}941942if (i == DatumCount)943{944break;945}946947/* Write merged datum to target buffer */948949memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,950ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,951BufferLength - BufferOffset));952953BufferOffset += ObjDesc->CommonField.AccessByteWidth;954MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;955}956957/* Mask off any extra bits in the last datum */958959BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;960if (BufferTailBits)961{962MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);963}964965/* Write the last datum to the buffer */966967memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,968ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,969BufferLength - BufferOffset));970971return_ACPI_STATUS (AE_OK);972}973974975/*******************************************************************************976*977* FUNCTION: AcpiExInsertIntoField978*979* PARAMETERS: ObjDesc - Field to be written980* Buffer - Data to be written981* BufferLength - Length of Buffer982*983* RETURN: Status984*985* DESCRIPTION: Store the Buffer contents into the given field986*987******************************************************************************/988989ACPI_STATUS990AcpiExInsertIntoField (991ACPI_OPERAND_OBJECT *ObjDesc,992void *Buffer,993UINT32 BufferLength)994{995void *NewBuffer;996ACPI_STATUS Status;997UINT64 Mask;998UINT64 WidthMask;999UINT64 MergedDatum;1000UINT64 RawDatum = 0;1001UINT32 FieldOffset = 0;1002UINT32 BufferOffset = 0;1003UINT32 BufferTailBits;1004UINT32 DatumCount;1005UINT32 FieldDatumCount;1006UINT32 AccessBitWidth;1007UINT32 RequiredLength;1008UINT32 i;100910101011ACPI_FUNCTION_TRACE (ExInsertIntoField);101210131014/* Validate input buffer */10151016NewBuffer = NULL;1017RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (1018ObjDesc->CommonField.BitLength);10191020/*1021* We must have a buffer that is at least as long as the field1022* we are writing to. This is because individual fields are1023* indivisible and partial writes are not supported -- as per1024* the ACPI specification.1025*/1026if (BufferLength < RequiredLength)1027{1028/* We need to create a new buffer */10291030NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);1031if (!NewBuffer)1032{1033return_ACPI_STATUS (AE_NO_MEMORY);1034}10351036/*1037* Copy the original data to the new buffer, starting1038* at Byte zero. All unused (upper) bytes of the1039* buffer will be 0.1040*/1041memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength);1042Buffer = NewBuffer;1043BufferLength = RequiredLength;1044}10451046/* TBD: Move to common setup code */10471048/* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */1049if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))1050{1051ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);1052}10531054AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);10551056/* Create the bitmasks used for bit insertion */10571058WidthMask = ACPI_MASK_BITS_ABOVE_64 (AccessBitWidth);1059Mask = WidthMask &1060ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);10611062/* Compute the number of datums (access width data items) */10631064DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,1065AccessBitWidth);10661067FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +1068ObjDesc->CommonField.StartFieldBitOffset,1069AccessBitWidth);10701071/* Get initial Datum from the input buffer */10721073memcpy (&RawDatum, Buffer,1074ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,1075BufferLength - BufferOffset));10761077MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;10781079/* Write the entire field */10801081for (i = 1; i < FieldDatumCount; i++)1082{1083/* Write merged datum to the target field */10841085MergedDatum &= Mask;1086Status = AcpiExWriteWithUpdateRule (1087ObjDesc, Mask, MergedDatum, FieldOffset);1088if (ACPI_FAILURE (Status))1089{1090goto Exit;1091}10921093FieldOffset += ObjDesc->CommonField.AccessByteWidth;10941095/*1096* Start new output datum by merging with previous input datum1097* if necessary.1098*1099* Note: Before the shift, check if the shift value will be larger than1100* the integer size. If so, there is no need to perform the operation.1101* This avoids the differences in behavior between different compilers1102* concerning shift values larger than the target data width.1103*/1104if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <1105ACPI_INTEGER_BIT_SIZE)1106{1107MergedDatum = RawDatum >>1108(AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);1109}1110else1111{1112MergedDatum = 0;1113}11141115Mask = WidthMask;11161117if (i == DatumCount)1118{1119break;1120}11211122/* Get the next input datum from the buffer */11231124BufferOffset += ObjDesc->CommonField.AccessByteWidth;1125memcpy (&RawDatum, ((char *) Buffer) + BufferOffset,1126ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,1127BufferLength - BufferOffset));11281129MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;1130}11311132/* Mask off any extra bits in the last datum */11331134BufferTailBits = (ObjDesc->CommonField.BitLength +1135ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;1136if (BufferTailBits)1137{1138Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);1139}11401141/* Write the last datum to the field */11421143MergedDatum &= Mask;1144Status = AcpiExWriteWithUpdateRule (1145ObjDesc, Mask, MergedDatum, FieldOffset);11461147Exit:1148/* Free temporary buffer if we used one */11491150if (NewBuffer)1151{1152ACPI_FREE (NewBuffer);1153}1154return_ACPI_STATUS (Status);1155}115611571158