ACPI_STATUS AcpiExExtractFromField ( ACPI_OPERAND_OBJECT *ObjDesc, void *Buffer, UINT32 BufferLength) { ACPI_STATUS Status; UINT64 RawDatum; UINT64 MergedDatum; UINT32 FieldOffset = 0; UINT32 BufferOffset = 0; UINT32 BufferTailBits; UINT32 DatumCount; UINT32 FieldDatumCount; UINT32 AccessBitWidth; UINT32 i; ACPI_FUNCTION_TRACE (ExExtractFromField); /* Validate target buffer and clear it */ if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) { ACPI_ERROR ((AE_INFO, "Field size %u (bits) is too large for buffer (%u)", ObjDesc->CommonField.BitLength, BufferLength)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } memset (Buffer, 0, BufferLength); AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); /* Handle the simple case here */ if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && (ObjDesc->CommonField.BitLength == AccessBitWidth)) { if (BufferLength >= sizeof (UINT64)) { Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); } else { /* Use RawDatum (UINT64) to handle buffers < 64 bits */ Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ); memcpy (Buffer, &RawDatum, BufferLength); } return_ACPI_STATUS (Status); } /* TBD: Move to common setup code */ /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) { ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); AccessBitWidth = sizeof (UINT64) * 8; } /* Compute the number of datums (access width data items) */ DatumCount = ACPI_ROUND_UP_TO ( ObjDesc->CommonField.BitLength, AccessBitWidth); FieldDatumCount = ACPI_ROUND_UP_TO ( ObjDesc->CommonField.BitLength + ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); /* Priming read from the field */ Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; /* Read the rest of the field */ for (i = 1; i < FieldDatumCount; i++) { /* Get next input datum from the field */ FieldOffset += ObjDesc->CommonField.AccessByteWidth; Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* * Merge with previous datum if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < ACPI_INTEGER_BIT_SIZE) { MergedDatum |= RawDatum << (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); } if (i == DatumCount) { break; } /* Write merged datum to target buffer */ memcpy (((char *) Buffer) + BufferOffset, &MergedDatum, ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, BufferLength - BufferOffset)); BufferOffset += ObjDesc->CommonField.AccessByteWidth; MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; } /* Mask off any extra bits in the last datum */ BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; if (BufferTailBits) { MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); } /* Write the last datum to the buffer */ memcpy (((char *) Buffer) + BufferOffset, &MergedDatum, ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, BufferLength - BufferOffset)); return_ACPI_STATUS (AE_OK); }
ACPI_STATUS AcpiExInsertIntoField ( ACPI_OPERAND_OBJECT *ObjDesc, void *Buffer, UINT32 BufferLength) { void *NewBuffer; ACPI_STATUS Status; UINT64 Mask; UINT64 WidthMask; UINT64 MergedDatum; UINT64 RawDatum = 0; UINT32 FieldOffset = 0; UINT32 BufferOffset = 0; UINT32 BufferTailBits; UINT32 DatumCount; UINT32 FieldDatumCount; UINT32 AccessBitWidth; UINT32 RequiredLength; UINT32 i; ACPI_FUNCTION_TRACE (ExInsertIntoField); /* Validate input buffer */ NewBuffer = NULL; RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( ObjDesc->CommonField.BitLength); /* * We must have a buffer that is at least as long as the field * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ if (BufferLength < RequiredLength) { /* We need to create a new buffer */ NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); if (!NewBuffer) { return_ACPI_STATUS (AE_NO_MEMORY); } /* * Copy the original data to the new buffer, starting * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength); Buffer = NewBuffer; BufferLength = RequiredLength; } /* TBD: Move to common setup code */ /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) { ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); } AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); /* * Create the bitmasks used for bit insertion. * Note: This if/else is used to bypass compiler differences with the * shift operator */ if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) { WidthMask = ACPI_UINT64_MAX; } else { WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); } Mask = WidthMask & ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); /* Compute the number of datums (access width data items) */ DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, AccessBitWidth); FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); /* Get initial Datum from the input buffer */ memcpy (&RawDatum, Buffer, ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, BufferLength - BufferOffset)); MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; /* Write the entire field */ for (i = 1; i < FieldDatumCount; i++) { /* Write merged datum to the target field */ MergedDatum &= Mask; Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, FieldOffset); if (ACPI_FAILURE (Status)) { goto Exit; } FieldOffset += ObjDesc->CommonField.AccessByteWidth; /* * Start new output datum by merging with previous input datum * if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE) { MergedDatum = RawDatum >> (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); } else {
acpi_status acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; u64 raw_datum; u64 merged_datum; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 access_bit_width; u32 i; ACPI_FUNCTION_TRACE(ex_extract_from_field); /* Validate target buffer and clear it */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { ACPI_ERROR((AE_INFO, "Field size %u (bits) is too large for buffer (%u)", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } ACPI_MEMSET(buffer, 0, buffer_length); access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); /* Handle the simple case here */ if ((obj_desc->common_field.start_field_bit_offset == 0) && (obj_desc->common_field.bit_length == access_bit_width)) { status = acpi_ex_field_datum_io(obj_desc, 0, buffer, ACPI_READ); return_ACPI_STATUS(status); } /* TBD: Move to common setup code */ /* Field algorithm is limited to sizeof(u64), truncate if needed */ if (obj_desc->common_field.access_byte_width > sizeof(u64)) { obj_desc->common_field.access_byte_width = sizeof(u64); access_bit_width = sizeof(u64) * 8; } /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, access_bit_width); field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, access_bit_width); /* Priming read from the field */ status = acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; /* Read the rest of the field */ for (i = 1; i < field_datum_count; i++) { /* Get next input datum from the field */ field_offset += obj_desc->common_field.access_byte_width; status = acpi_ex_field_datum_io(obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } /* * Merge with previous datum if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if (access_bit_width - obj_desc->common_field.start_field_bit_offset < ACPI_INTEGER_BIT_SIZE) { merged_datum |= raw_datum << (access_bit_width - obj_desc->common_field. start_field_bit_offset); } if (i == datum_count) { break; } /* Write merged datum to target buffer */ ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); buffer_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; } /* Mask off any extra bits in the last datum */ buffer_tail_bits = obj_desc->common_field.bit_length % access_bit_width; if (buffer_tail_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE(buffer_tail_bits); } /* Write the last datum to the buffer */ ACPI_MEMCPY(((char *)buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); return_ACPI_STATUS(AE_OK); }
acpi_status acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { void *new_buffer; acpi_status status; u64 mask; u64 width_mask; u64 merged_datum; u64 raw_datum = 0; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 access_bit_width; u32 required_length; u32 i; ACPI_FUNCTION_TRACE(ex_insert_into_field); /* Validate input buffer */ new_buffer = NULL; required_length = ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); /* * We must have a buffer that is at least as long as the field * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ if (buffer_length < required_length) { /* We need to create a new buffer */ new_buffer = ACPI_ALLOCATE_ZEROED(required_length); if (!new_buffer) { return_ACPI_STATUS(AE_NO_MEMORY); } /* * Copy the original data to the new buffer, starting * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); buffer = new_buffer; buffer_length = required_length; } /* TBD: Move to common setup code */ /* Algo is limited to sizeof(u64), so cut the access_byte_width */ if (obj_desc->common_field.access_byte_width > sizeof(u64)) { obj_desc->common_field.access_byte_width = sizeof(u64); } access_bit_width = ACPI_MUL_8(obj_desc->common_field.access_byte_width); /* * Create the bitmasks used for bit insertion. * Note: This if/else is used to bypass compiler differences with the * shift operator */ if (access_bit_width == ACPI_INTEGER_BIT_SIZE) { width_mask = ACPI_UINT64_MAX; } else { width_mask = ACPI_MASK_BITS_ABOVE(access_bit_width); } mask = width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, access_bit_width); field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, access_bit_width); /* Get initial Datum from the input buffer */ ACPI_MEMCPY(&raw_datum, buffer, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; /* Write the entire field */ for (i = 1; i < field_datum_count; i++) { /* Write merged datum to the target field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, field_offset); if (ACPI_FAILURE(status)) { goto exit; } field_offset += obj_desc->common_field.access_byte_width; /* * Start new output datum by merging with previous input datum * if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((access_bit_width - obj_desc->common_field.start_field_bit_offset) < ACPI_INTEGER_BIT_SIZE) { merged_datum = raw_datum >> (access_bit_width - obj_desc->common_field. start_field_bit_offset); } else {
static acpi_status acpi_db_test_buffer_type(struct acpi_namespace_node *node, u32 bit_length) { union acpi_object *temp1 = NULL; union acpi_object *temp2 = NULL; union acpi_object *temp3 = NULL; u8 *buffer; union acpi_object write_value; acpi_status status; u32 byte_length; u32 i; u8 extra_bits; byte_length = ACPI_ROUND_BITS_UP_TO_BYTES(bit_length); if (byte_length == 0) { acpi_os_printf(" Ignoring zero length buffer"); return (AE_OK); } /* Allocate a local buffer */ buffer = ACPI_ALLOCATE_ZEROED(byte_length); if (!buffer) { return (AE_NO_MEMORY); } /* Read the original value */ status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp1); if (ACPI_FAILURE(status)) { goto exit; } /* Emit a few bytes of the buffer */ acpi_os_printf(" (%4.4X/%3.3X)", bit_length, temp1->buffer.length); for (i = 0; ((i < 4) && (i < byte_length)); i++) { acpi_os_printf(" %2.2X", temp1->buffer.pointer[i]); } acpi_os_printf("... "); /* * Write a new value. * * Handle possible extra bits at the end of the buffer. Can * happen for field_units larger than an integer, but the bit * count is not an integral number of bytes. Zero out the * unused bits. */ memset(buffer, BUFFER_FILL_VALUE, byte_length); extra_bits = bit_length % 8; if (extra_bits) { buffer[byte_length - 1] = ACPI_MASK_BITS_ABOVE(extra_bits); } write_value.type = ACPI_TYPE_BUFFER; write_value.buffer.length = byte_length; write_value.buffer.pointer = buffer; status = acpi_db_write_to_object(node, &write_value); if (ACPI_FAILURE(status)) { goto exit; } /* Ensure that we can read back the new value */ status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp2); if (ACPI_FAILURE(status)) { goto exit; } if (memcmp(temp2->buffer.pointer, buffer, byte_length)) { acpi_os_printf(" MISMATCH 2: New buffer value"); } /* Write back the original value */ write_value.buffer.length = byte_length; write_value.buffer.pointer = temp1->buffer.pointer; status = acpi_db_write_to_object(node, &write_value); if (ACPI_FAILURE(status)) { goto exit; } /* Ensure that we can read back the original value */ status = acpi_db_read_from_object(node, ACPI_TYPE_BUFFER, &temp3); if (ACPI_FAILURE(status)) { goto exit; } if (memcmp(temp1->buffer.pointer, temp3->buffer.pointer, byte_length)) { acpi_os_printf(" MISMATCH 3: While restoring original buffer"); } exit: ACPI_FREE(buffer); if (temp1) { acpi_os_free(temp1); } if (temp2) { acpi_os_free(temp2); } if (temp3) { acpi_os_free(temp3); } return (status); }
static ACPI_STATUS AcpiDbTestBufferType ( ACPI_NAMESPACE_NODE *Node, UINT32 BitLength) { ACPI_OBJECT *Temp1 = NULL; ACPI_OBJECT *Temp2 = NULL; ACPI_OBJECT *Temp3 = NULL; UINT8 *Buffer; ACPI_OBJECT WriteValue; ACPI_STATUS Status; UINT32 ByteLength; UINT32 i; UINT8 ExtraBits; ByteLength = ACPI_ROUND_BITS_UP_TO_BYTES (BitLength); if (ByteLength == 0) { AcpiOsPrintf (" Ignoring zero length buffer"); return (AE_OK); } /* Allocate a local buffer */ Buffer = ACPI_ALLOCATE_ZEROED (ByteLength); if (!Buffer) { return (AE_NO_MEMORY); } /* Read the original value */ Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp1); if (ACPI_FAILURE (Status)) { goto Exit; } /* Emit a few bytes of the buffer */ AcpiOsPrintf (" (%4.4X/%3.3X)", BitLength, Temp1->Buffer.Length); for (i = 0; ((i < 4) && (i < ByteLength)); i++) { AcpiOsPrintf (" %2.2X", Temp1->Buffer.Pointer[i]); } AcpiOsPrintf ("... "); /* * Write a new value. * * Handle possible extra bits at the end of the buffer. Can * happen for FieldUnits larger than an integer, but the bit * count is not an integral number of bytes. Zero out the * unused bits. */ memset (Buffer, BUFFER_FILL_VALUE, ByteLength); ExtraBits = BitLength % 8; if (ExtraBits) { Buffer [ByteLength - 1] = ACPI_MASK_BITS_ABOVE (ExtraBits); } WriteValue.Type = ACPI_TYPE_BUFFER; WriteValue.Buffer.Length = ByteLength; WriteValue.Buffer.Pointer = Buffer; Status = AcpiDbWriteToObject (Node, &WriteValue); if (ACPI_FAILURE (Status)) { goto Exit; } /* Ensure that we can read back the new value */ Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp2); if (ACPI_FAILURE (Status)) { goto Exit; } if (memcmp (Temp2->Buffer.Pointer, Buffer, ByteLength)) { AcpiOsPrintf (" MISMATCH 2: New buffer value"); } /* Write back the original value */ WriteValue.Buffer.Length = ByteLength; WriteValue.Buffer.Pointer = Temp1->Buffer.Pointer; Status = AcpiDbWriteToObject (Node, &WriteValue); if (ACPI_FAILURE (Status)) { goto Exit; } /* Ensure that we can read back the original value */ Status = AcpiDbReadFromObject (Node, ACPI_TYPE_BUFFER, &Temp3); if (ACPI_FAILURE (Status)) { goto Exit; } if (memcmp (Temp1->Buffer.Pointer, Temp3->Buffer.Pointer, ByteLength)) { AcpiOsPrintf (" MISMATCH 3: While restoring original buffer"); } Exit: ACPI_FREE (Buffer); if (Temp1) {AcpiOsFree (Temp1);} if (Temp2) {AcpiOsFree (Temp2);} if (Temp3) {AcpiOsFree (Temp3);} return (Status); }
ACPI_STATUS AcpiHwWrite ( UINT32 Value, ACPI_GENERIC_ADDRESS *Reg) { UINT64 Address; UINT8 AccessWidth; UINT32 BitWidth; UINT8 BitOffset; UINT64 Value64; UINT32 NewValue32, OldValue32; UINT8 Index; ACPI_STATUS Status; ACPI_FUNCTION_NAME (HwWrite); /* Validate contents of the GAS register */ Status = AcpiHwValidateRegister (Reg, 32, &Address); if (ACPI_FAILURE (Status)) { return (Status); } /* Convert AccessWidth into number of bits based */ AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1; AccessWidth = 1 << (AccessWidth + 2); BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth); BitOffset = Reg->BitOffset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ Index = 0; while (BitWidth) { NewValue32 = ACPI_GET_BITS (&Value, (Index * AccessWidth), ((1 << AccessWidth) - 1)); if (BitOffset > AccessWidth) { BitOffset -= AccessWidth; } else { if (BitOffset) { NewValue32 &= ACPI_MASK_BITS_BELOW (BitOffset); } if (BitWidth < AccessWidth) { NewValue32 &= ACPI_MASK_BITS_ABOVE (BitWidth); } if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) { if (BitOffset || BitWidth < AccessWidth) { /* * Read old values in order not to modify the bits that * are beyond the register BitWidth/BitOffset setting. */ Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), &Value64, AccessWidth); OldValue32 = (UINT32) Value64; if (BitOffset) { OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1); BitOffset = 0; } if (BitWidth < AccessWidth) { OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1); } NewValue32 |= OldValue32; } Value64 = (UINT64) NewValue32; Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), Value64, AccessWidth); } else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ { if (BitOffset || BitWidth < AccessWidth) { /* * Read old values in order not to modify the bits that * are beyond the register BitWidth/BitOffset setting. */ Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), &OldValue32, AccessWidth); if (BitOffset) { OldValue32 &= ACPI_MASK_BITS_ABOVE (BitOffset + 1); BitOffset = 0; } if (BitWidth < AccessWidth) { OldValue32 &= ACPI_MASK_BITS_BELOW (BitWidth - 1); } NewValue32 |= OldValue32; } Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), NewValue32, AccessWidth); } } BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; Index++; } ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId))); return (Status); }
acpi_status acpi_ex_extract_from_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; u32 field_datum_byte_offset; u32 datum_offset; acpi_integer previous_raw_datum; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); /* * The field must fit within the caller's buffer */ byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (byte_field_length > buffer_length) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field size %X (bytes) too large for buffer (%X)\n", byte_field_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Convert field byte count to datum count, round up if necessary */ datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "byte_len %X, datum_len %X, byte_gran %X\n", byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where a byte is read, * but the buffer is really a u32 (4 bytes). */ ACPI_MEMSET (buffer, 0, buffer_length); /* Read the first raw datum to prime the loop */ field_datum_byte_offset = 0; datum_offset= 0; status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &previous_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* We might actually be done if the request fits in one datum */ if ((datum_count == 1) && (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { /* 1) Shift the valid data bits down to start at bit 0 */ merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Mask off any upper unused bits (bits not part of the field) */ if (obj_desc->common_field.end_buffer_valid_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } /* Store the datum to the caller buffer */ acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, datum_offset); return_ACPI_STATUS (AE_OK); }
acpi_status acpi_ex_insert_into_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; acpi_integer mask; acpi_integer merged_datum; acpi_integer raw_datum = 0; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 i; ACPI_FUNCTION_TRACE ("ex_insert_into_field"); /* Validate input buffer */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( obj_desc->common_field.bit_length)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field size %X (bits) is too large for buffer (%X)\n", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Compute the number of datums (access width data items) */ mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); field_datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length + obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.access_bit_width); /* Get initial Datum from the input buffer */ ACPI_MEMCPY (&raw_datum, buffer, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; /* Write the entire field */ for (i = 1; i < field_datum_count; i++) { /* Write merged datum to the target field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Start new output datum by merging with previous input datum */ field_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); mask = ACPI_INTEGER_MAX; if (i == datum_count) { break; } /* Get the next input datum from the buffer */ buffer_offset += obj_desc->common_field.access_byte_width; ACPI_MEMCPY (&raw_datum, ((char *) buffer) + buffer_offset, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; } /* Mask off any extra bits in the last datum */ buffer_tail_bits = (obj_desc->common_field.bit_length + obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } /* Write the last datum to the field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); return_ACPI_STATUS (status); }
ACPI_STATUS AcpiHwRead ( UINT32 *Value, ACPI_GENERIC_ADDRESS *Reg) { UINT64 Address; UINT8 AccessWidth; UINT32 BitWidth; UINT8 BitOffset; UINT64 Value64; UINT32 Value32; UINT8 Index; ACPI_STATUS Status; ACPI_FUNCTION_NAME (HwRead); /* Validate contents of the GAS register */ Status = AcpiHwValidateRegister (Reg, 32, &Address); if (ACPI_FAILURE (Status)) { return (Status); } /* * Initialize entire 32-bit return value to zero, convert AccessWidth * into number of bits based */ *Value = 0; AccessWidth = Reg->AccessWidth ? Reg->AccessWidth : 1; AccessWidth = 1 << (AccessWidth + 2); BitWidth = ACPI_ROUND_UP (Reg->BitOffset + Reg->BitWidth, AccessWidth); BitOffset = Reg->BitOffset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ Index = 0; while (BitWidth) { if (BitOffset > AccessWidth) { Value32 = 0; BitOffset -= AccessWidth; } else { if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) { Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), &Value64, AccessWidth); Value32 = (UINT32) Value64; } else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ { Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) Address + Index * ACPI_DIV_8 (AccessWidth), &Value32, AccessWidth); } if (BitOffset) { Value32 &= ACPI_MASK_BITS_BELOW (BitOffset); BitOffset = 0; } if (BitWidth < AccessWidth) { Value32 &= ACPI_MASK_BITS_ABOVE (BitWidth); } } ACPI_SET_BITS (Value, Index * AccessWidth, ((1 << AccessWidth) - 1), Value32); BitWidth -= BitWidth > AccessWidth ? AccessWidth : BitWidth; Index++; } ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *Value, AccessWidth, ACPI_FORMAT_UINT64 (Address), AcpiUtGetRegionName (Reg->SpaceId))); return (Status); }
acpi_status acpi_ex_extract_from_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; acpi_integer raw_datum; acpi_integer merged_datum; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 i; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); /* Validate target buffer and clear it */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( obj_desc->common_field.bit_length)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field size %X (bits) is too large for buffer (%X)\n", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } ACPI_MEMSET (buffer, 0, buffer_length); /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO ( obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); field_datum_count = ACPI_ROUND_UP_TO ( obj_desc->common_field.bit_length + obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.access_bit_width); /* Priming read from the field */ status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; /* Read the rest of the field */ for (i = 1; i < field_datum_count; i++) { /* Get next input datum from the field */ field_offset += obj_desc->common_field.access_byte_width; status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* Merge with previous datum if necessary */ merged_datum |= raw_datum << (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); if (i == datum_count) { break; } /* Write merged datum to target buffer */ ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); buffer_offset += obj_desc->common_field.access_byte_width; merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; } /* Mask off any extra bits in the last datum */ buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; if (buffer_tail_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); } /* Write the last datum to the buffer */ ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); return_ACPI_STATUS (AE_OK); }
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u32 new_value32, old_value32; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* Convert access_width into number of bits based */ access_width = acpi_hw_get_access_bit_width(reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { /* * Use offset style bit reads because "Index * AccessWidth" is * ensured to be less than 32-bits by acpi_hw_validate_register(). */ new_value32 = ACPI_GET_BITS(&value, index * access_width, ACPI_MASK_BITS_ABOVE_32 (access_width)); if (bit_offset >= access_width) { bit_offset -= access_width; } else { /* * Use offset style bit masks because access_width is ensured * to be less than 32-bits by acpi_hw_validate_register() and * bit_offset/bit_width is less than access_width here. */ if (bit_offset) { new_value32 &= ACPI_MASK_BITS_BELOW(bit_offset); } if (bit_width < access_width) { new_value32 &= ACPI_MASK_BITS_ABOVE(bit_width); } if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { if (bit_offset || bit_width < access_width) { /* * Read old values in order not to modify the bits that * are beyond the register bit_width/bit_offset setting. */ status = acpi_os_read_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), &value64, access_width); old_value32 = (u32)value64; /* * Use offset style bit masks because access_width is * ensured to be less than 32-bits by * acpi_hw_validate_register() and bit_offset/bit_width is * less than access_width here. */ if (bit_offset) { old_value32 &= ACPI_MASK_BITS_ABOVE (bit_offset); bit_offset = 0; } if (bit_width < access_width) { old_value32 &= ACPI_MASK_BITS_BELOW (bit_width); } new_value32 |= old_value32; } value64 = (u64)new_value32; status = acpi_os_write_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), value64, access_width); } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ if (bit_offset || bit_width < access_width) { /* * Read old values in order not to modify the bits that * are beyond the register bit_width/bit_offset setting. */ status = acpi_hw_read_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), &old_value32, access_width); /* * Use offset style bit masks because access_width is * ensured to be less than 32-bits by * acpi_hw_validate_register() and bit_offset/bit_width is * less than access_width here. */ if (bit_offset) { old_value32 &= ACPI_MASK_BITS_ABOVE (bit_offset); bit_offset = 0; } if (bit_width < access_width) { old_value32 &= ACPI_MASK_BITS_BELOW (bit_width); } new_value32 |= old_value32; } status = acpi_hw_write_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), new_value32, access_width); } } /* * Index * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) { u64 address; u8 access_width; u32 bit_width; u8 bit_offset; u64 value64; u32 value32; u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_read); /* Validate contents of the GAS register */ status = acpi_hw_validate_register(reg, 32, &address); if (ACPI_FAILURE(status)) { return (status); } /* * Initialize entire 32-bit return value to zero, convert access_width * into number of bits based */ *value = 0; access_width = acpi_hw_get_access_bit_width(reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ index = 0; while (bit_width) { if (bit_offset >= access_width) { value32 = 0; bit_offset -= access_width; } else { if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { status = acpi_os_read_memory((acpi_physical_address) address + index * ACPI_DIV_8 (access_width), &value64, access_width); value32 = (u32)value64; } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ status = acpi_hw_read_port((acpi_io_address) address + index * ACPI_DIV_8 (access_width), &value32, access_width); } /* * Use offset style bit masks because: * bit_offset < access_width/bit_width < access_width, and * access_width is ensured to be less than 32-bits by * acpi_hw_validate_register(). */ if (bit_offset) { value32 &= ACPI_MASK_BITS_BELOW(bit_offset); bit_offset = 0; } if (bit_width < access_width) { value32 &= ACPI_MASK_BITS_ABOVE(bit_width); } } /* * Use offset style bit writes because "Index * AccessWidth" is * ensured to be less than 32-bits by acpi_hw_validate_register(). */ ACPI_SET_BITS(value, index * access_width, ACPI_MASK_BITS_ABOVE_32(access_width), value32); bit_width -= bit_width > access_width ? access_width : bit_width; index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", *value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); }
acpi_status acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; acpi_integer mask; acpi_integer width_mask; acpi_integer merged_datum; acpi_integer raw_datum = 0; u32 field_offset = 0; u32 buffer_offset = 0; u32 buffer_tail_bits; u32 datum_count; u32 field_datum_count; u32 i; ACPI_FUNCTION_TRACE(ex_insert_into_field); /* Validate input buffer */ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) { ACPI_ERROR((AE_INFO, "Field size %X (bits) is too large for buffer (%X)", obj_desc->common_field.bit_length, buffer_length)); return_ACPI_STATUS(AE_BUFFER_OVERFLOW); } /* * Create the bitmasks used for bit insertion. * Note: This if/else is used to bypass compiler differences with the * shift operator */ if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) { width_mask = ACPI_INTEGER_MAX; } else { width_mask = ACPI_MASK_BITS_ABOVE(obj_desc->common_field. access_bit_width); } mask = width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset); /* Compute the number of datums (access width data items) */ datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length, obj_desc->common_field.access_bit_width); field_datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field. access_bit_width); /* Get initial Datum from the input buffer */ ACPI_MEMCPY(&raw_datum, buffer, ACPI_MIN(obj_desc->common_field.access_byte_width, buffer_length - buffer_offset)); merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; /* Write the entire field */ for (i = 1; i < field_datum_count; i++) { /* Write merged datum to the target field */ merged_datum &= mask; status = acpi_ex_write_with_update_rule(obj_desc, mask, merged_datum, field_offset); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } field_offset += obj_desc->common_field.access_byte_width; /* * Start new output datum by merging with previous input datum * if necessary. * * Note: Before the shift, check if the shift value will be larger than * the integer size. If so, there is no need to perform the operation. * This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ if ((obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset) < ACPI_INTEGER_BIT_SIZE) { merged_datum = raw_datum >> (obj_desc->common_field. access_bit_width - obj_desc->common_field. start_field_bit_offset); } else {
acpi_status acpi_ex_extract_from_field ( union acpi_operand_object *obj_desc, void *buffer, u32 buffer_length) { acpi_status status; u32 field_datum_byte_offset; u32 buffer_datum_offset; acpi_integer previous_raw_datum = 0; acpi_integer this_raw_datum = 0; acpi_integer merged_datum = 0; u32 byte_field_length; u32 datum_count; u32 i; ACPI_FUNCTION_TRACE ("ex_extract_from_field"); /* * The field must fit within the caller's buffer */ byte_field_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); if (byte_field_length > buffer_length) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field size %X (bytes) too large for buffer (%X)\n", byte_field_length, buffer_length)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } /* Convert field byte count to datum count, round up if necessary */ datum_count = ACPI_ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); /* * If the field is not aligned on a datum boundary and does not * fit within a single datum, we must read an extra datum. * * We could just split the aligned and non-aligned cases since the * aligned case is so very simple, but this would require more code. */ if ((obj_desc->common_field.end_field_valid_bits != 0) && (!(obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM))) { datum_count++; } ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "byte_len %X, datum_len %X, byte_gran %X\n", byte_field_length, datum_count,obj_desc->common_field.access_byte_width)); /* * Clear the caller's buffer (the whole buffer length as given) * This is very important, especially in the cases where the buffer * is longer than the size of the field. */ ACPI_MEMSET (buffer, 0, buffer_length); field_datum_byte_offset = 0; buffer_datum_offset= 0; /* Read the entire field */ for (i = 0; i < datum_count; i++) { status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, &this_raw_datum, ACPI_READ); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } /* We might actually be done if the request fits in one datum */ if ((datum_count == 1) && (obj_desc->common_field.flags & AOPOBJ_SINGLE_DATUM)) { /* 1) Shift the valid data bits down to start at bit 0 */ merged_datum = (this_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Mask off any upper unused bits (bits not part of the field) */ if (obj_desc->common_field.end_buffer_valid_bits) { merged_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); } /* Store the datum to the caller buffer */ acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); return_ACPI_STATUS (AE_OK); } /* Special handling for the last datum to ignore extra bits */ if ((i >= (datum_count -1)) && (obj_desc->common_field.end_field_valid_bits)) { /* * This is the last iteration of the loop. We need to clear * any unused bits (bits that are not part of this field) before * we store the final merged datum into the caller buffer. */ this_raw_datum &= ACPI_MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); } /* * Create the (possibly) merged datum to be stored to the caller buffer */ if (obj_desc->common_field.start_field_bit_offset == 0) { /* Field is not skewed and we can just copy the datum */ acpi_ex_set_buffer_datum (this_raw_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } else { /* Not aligned -- on the first iteration, just save the datum */ if (i != 0) { /* * Put together the appropriate bits of the two raw data to make a * single complete field datum * * 1) Normalize the first datum down to bit 0 */ merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); /* 2) Insert the second datum "above" the first datum */ merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); acpi_ex_set_buffer_datum (merged_datum, buffer, buffer_length, obj_desc->common_field.access_byte_width, buffer_datum_offset); buffer_datum_offset++; } /* * Save the raw datum that was just acquired since it may contain bits * of the *next* field datum */ previous_raw_datum = this_raw_datum; }