Esempio n. 1
0
ACPI_STATUS
AcpiGetTimerDuration (
    UINT32                  StartTicks,
    UINT32                  EndTicks,
    UINT32                  *TimeElapsed)
{
    ACPI_STATUS             Status;
    UINT32                  DeltaTicks;
    UINT64                  Quotient;


    ACPI_FUNCTION_TRACE (AcpiGetTimerDuration);


    if (!TimeElapsed)
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    /*
     * Compute Tick Delta:
     * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
     */
    if (StartTicks < EndTicks)
    {
        DeltaTicks = EndTicks - StartTicks;
    }
    else if (StartTicks > EndTicks)
    {
        if ((AcpiGbl_FADT.Flags & ACPI_FADT_32BIT_TIMER) == 0)
        {
            /* 24-bit Timer */

            DeltaTicks = (((0x00FFFFFF - StartTicks) + EndTicks) & 0x00FFFFFF);
        }
        else
        {
            /* 32-bit Timer */

            DeltaTicks = (0xFFFFFFFF - StartTicks) + EndTicks;
        }
    }
    else /* StartTicks == EndTicks */
    {
        *TimeElapsed = 0;
        return_ACPI_STATUS (AE_OK);
    }

    /*
     * Compute Duration (Requires a 64-bit multiply and divide):
     *
     * TimeElapsed (microseconds) =
     *  (DeltaTicks * ACPI_USEC_PER_SEC) / ACPI_PM_TIMER_FREQUENCY;
     */
    Status = AcpiUtShortDivide (((UINT64) DeltaTicks) * ACPI_USEC_PER_SEC,
                                ACPI_PM_TIMER_FREQUENCY, &Quotient, NULL);

    *TimeElapsed = (UINT32) Quotient;
    return_ACPI_STATUS (Status);
}
Esempio n. 2
0
ACPI_STATUS
AcpiExOpcode_1A_1T_1R (
    ACPI_WALK_STATE         *WalkState)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_OPERAND_OBJECT     **Operand = &WalkState->Operands[0];
    ACPI_OPERAND_OBJECT     *ReturnDesc = NULL;
    ACPI_OPERAND_OBJECT     *ReturnDesc2 = NULL;
    UINT32                  Temp32;
    UINT32                  i;
    UINT64                  PowerOfTen;
    UINT64                  Digit;


    ACPI_FUNCTION_TRACE_STR (ExOpcode_1A_1T_1R,
        AcpiPsGetOpcodeName (WalkState->Opcode));


    /* Examine the AML opcode */

    switch (WalkState->Opcode)
    {
    case AML_BIT_NOT_OP:
    case AML_FIND_SET_LEFT_BIT_OP:
    case AML_FIND_SET_RIGHT_BIT_OP:
    case AML_FROM_BCD_OP:
    case AML_TO_BCD_OP:
    case AML_COND_REF_OF_OP:

        /* Create a return object of type Integer for these opcodes */

        ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER);
        if (!ReturnDesc)
        {
            Status = AE_NO_MEMORY;
            goto Cleanup;
        }

        switch (WalkState->Opcode)
        {
        case AML_BIT_NOT_OP:            /* Not (Operand, Result)  */

            ReturnDesc->Integer.Value = ~Operand[0]->Integer.Value;
            break;

        case AML_FIND_SET_LEFT_BIT_OP:  /* FindSetLeftBit (Operand, Result) */

            ReturnDesc->Integer.Value = Operand[0]->Integer.Value;

            /*
             * Acpi specification describes Integer type as a little
             * endian unsigned value, so this boundary condition is valid.
             */
            for (Temp32 = 0; ReturnDesc->Integer.Value &&
                    Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32)
            {
                ReturnDesc->Integer.Value >>= 1;
            }

            ReturnDesc->Integer.Value = Temp32;
            break;

        case AML_FIND_SET_RIGHT_BIT_OP: /* FindSetRightBit (Operand, Result) */

            ReturnDesc->Integer.Value = Operand[0]->Integer.Value;

            /*
             * The Acpi specification describes Integer type as a little
             * endian unsigned value, so this boundary condition is valid.
             */
            for (Temp32 = 0; ReturnDesc->Integer.Value &&
                     Temp32 < ACPI_INTEGER_BIT_SIZE; ++Temp32)
            {
                ReturnDesc->Integer.Value <<= 1;
            }

            /* Since the bit position is one-based, subtract from 33 (65) */

            ReturnDesc->Integer.Value =
                Temp32 == 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - Temp32;
            break;

        case AML_FROM_BCD_OP:           /* FromBcd (BCDValue, Result)  */
            /*
             * The 64-bit ACPI integer can hold 16 4-bit BCD characters
             * (if table is 32-bit, integer can hold 8 BCD characters)
             * Convert each 4-bit BCD value
             */
            PowerOfTen = 1;
            ReturnDesc->Integer.Value = 0;
            Digit = Operand[0]->Integer.Value;

            /* Convert each BCD digit (each is one nybble wide) */

            for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++)
            {
                /* Get the least significant 4-bit BCD digit */

                Temp32 = ((UINT32) Digit) & 0xF;

                /* Check the range of the digit */

                if (Temp32 > 9)
                {
                    ACPI_ERROR ((AE_INFO,
                        "BCD digit too large (not decimal): 0x%X",
                        Temp32));

                    Status = AE_AML_NUMERIC_OVERFLOW;
                    goto Cleanup;
                }

                /* Sum the digit into the result with the current power of 10 */

                ReturnDesc->Integer.Value +=
                    (((UINT64) Temp32) * PowerOfTen);

                /* Shift to next BCD digit */

                Digit >>= 4;

                /* Next power of 10 */

                PowerOfTen *= 10;
            }
            break;

        case AML_TO_BCD_OP:             /* ToBcd (Operand, Result)  */

            ReturnDesc->Integer.Value = 0;
            Digit = Operand[0]->Integer.Value;

            /* Each BCD digit is one nybble wide */

            for (i = 0; (i < AcpiGbl_IntegerNybbleWidth) && (Digit > 0); i++)
            {
                (void) AcpiUtShortDivide (Digit, 10, &Digit, &Temp32);

                /*
                 * Insert the BCD digit that resides in the
                 * remainder from above
                 */
                ReturnDesc->Integer.Value |=
                    (((UINT64) Temp32) << ACPI_MUL_4 (i));
            }

            /* Overflow if there is any data left in Digit */

            if (Digit > 0)
            {
                ACPI_ERROR ((AE_INFO,
                    "Integer too large to convert to BCD: 0x%8.8X%8.8X",
                    ACPI_FORMAT_UINT64 (Operand[0]->Integer.Value)));
                Status = AE_AML_NUMERIC_OVERFLOW;
                goto Cleanup;
            }
            break;

        case AML_COND_REF_OF_OP:        /* CondRefOf (SourceObject, Result)  */
            /*
             * This op is a little strange because the internal return value is
             * different than the return value stored in the result descriptor
             * (There are really two return values)
             */
            if ((ACPI_NAMESPACE_NODE *) Operand[0] == AcpiGbl_RootNode)
            {
                /*
                 * This means that the object does not exist in the namespace,
                 * return FALSE
                 */
                ReturnDesc->Integer.Value = 0;
                goto Cleanup;
            }

            /* Get the object reference, store it, and remove our reference */

            Status = AcpiExGetObjectReference (Operand[0],
                &ReturnDesc2, WalkState);
            if (ACPI_FAILURE (Status))
            {
                goto Cleanup;
            }

            Status = AcpiExStore (ReturnDesc2, Operand[1], WalkState);
            AcpiUtRemoveReference (ReturnDesc2);

            /* The object exists in the namespace, return TRUE */

            ReturnDesc->Integer.Value = ACPI_UINT64_MAX;
            goto Cleanup;


        default:

            /* No other opcodes get here */

            break;
        }
        break;

    case AML_STORE_OP:              /* Store (Source, Target) */
        /*
         * A store operand is typically a number, string, buffer or lvalue
         * Be careful about deleting the source object,
         * since the object itself may have been stored.
         */
        Status = AcpiExStore (Operand[0], Operand[1], WalkState);
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        /* It is possible that the Store already produced a return object */

        if (!WalkState->ResultObj)
        {
            /*
             * Normally, we would remove a reference on the Operand[0]
             * parameter; But since it is being used as the internal return
             * object (meaning we would normally increment it), the two
             * cancel out, and we simply don't do anything.
             */
            WalkState->ResultObj = Operand[0];
            WalkState->Operands[0] = NULL;  /* Prevent deletion */
        }
        return_ACPI_STATUS (Status);

    /*
     * ACPI 2.0 Opcodes
     */
    case AML_COPY_OP:               /* Copy (Source, Target) */

        Status = AcpiUtCopyIobjectToIobject (
            Operand[0], &ReturnDesc, WalkState);
        break;

    case AML_TO_DECSTRING_OP:       /* ToDecimalString (Data, Result) */

        Status = AcpiExConvertToString (
            Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_DECIMAL);
        if (ReturnDesc == Operand[0])
        {
            /* No conversion performed, add ref to handle return value */

            AcpiUtAddReference (ReturnDesc);
        }
        break;

    case AML_TO_HEXSTRING_OP:       /* ToHexString (Data, Result) */

        Status = AcpiExConvertToString (
            Operand[0], &ReturnDesc, ACPI_EXPLICIT_CONVERT_HEX);
        if (ReturnDesc == Operand[0])
        {
            /* No conversion performed, add ref to handle return value */

            AcpiUtAddReference (ReturnDesc);
        }
        break;

    case AML_TO_BUFFER_OP:          /* ToBuffer (Data, Result) */

        Status = AcpiExConvertToBuffer (Operand[0], &ReturnDesc);
        if (ReturnDesc == Operand[0])
        {
            /* No conversion performed, add ref to handle return value */

            AcpiUtAddReference (ReturnDesc);
        }
        break;

    case AML_TO_INTEGER_OP:         /* ToInteger (Data, Result) */

        /* Perform "explicit" conversion */

        Status = AcpiExConvertToInteger (Operand[0], &ReturnDesc, 0);
        if (ReturnDesc == Operand[0])
        {
            /* No conversion performed, add ref to handle return value */

            AcpiUtAddReference (ReturnDesc);
        }
        break;

    case AML_SHIFT_LEFT_BIT_OP:     /* ShiftLeftBit (Source, BitNum)  */
    case AML_SHIFT_RIGHT_BIT_OP:    /* ShiftRightBit (Source, BitNum) */

        /* These are two obsolete opcodes */

        ACPI_ERROR ((AE_INFO,
            "%s is obsolete and not implemented",
            AcpiPsGetOpcodeName (WalkState->Opcode)));
        Status = AE_SUPPORT;
        goto Cleanup;

    default:                        /* Unknown opcode */

        ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X",
            WalkState->Opcode));
        Status = AE_AML_BAD_OPCODE;
        goto Cleanup;
    }

    if (ACPI_SUCCESS (Status))
    {
        /* Store the return value computed above into the target object */

        Status = AcpiExStore (ReturnDesc, Operand[1], WalkState);
    }


Cleanup:

    /* Delete return object on error */

    if (ACPI_FAILURE (Status))
    {
        AcpiUtRemoveReference (ReturnDesc);
    }

    /* Save return object on success */

    else if (!WalkState->ResultObj)
    {
        WalkState->ResultObj = ReturnDesc;
    }

    return_ACPI_STATUS (Status);
}
Esempio n. 3
0
static UINT32
AcpiExConvertToAscii (
    UINT64                  Integer,
    UINT16                  Base,
    UINT8                   *String,
    UINT8                   DataWidth)
{
    UINT64                  Digit;
    UINT32                  i;
    UINT32                  j;
    UINT32                  k = 0;
    UINT32                  HexLength;
    UINT32                  DecimalLength;
    UINT32                  Remainder;
    BOOLEAN                 SupressZeros;


    ACPI_FUNCTION_ENTRY ();


    switch (Base)
    {
    case 10:

        /* Setup max length for the decimal number */

        switch (DataWidth)
        {
        case 1:

            DecimalLength = ACPI_MAX8_DECIMAL_DIGITS;
            break;

        case 4:

            DecimalLength = ACPI_MAX32_DECIMAL_DIGITS;
            break;

        case 8:
        default:

            DecimalLength = ACPI_MAX64_DECIMAL_DIGITS;
            break;
        }

        SupressZeros = TRUE;     /* No leading zeros */
        Remainder = 0;

        for (i = DecimalLength; i > 0; i--)
        {
            /* Divide by nth factor of 10 */

            Digit = Integer;
            for (j = 0; j < i; j++)
            {
                (void) AcpiUtShortDivide (Digit, 10, &Digit, &Remainder);
            }

            /* Handle leading zeros */

            if (Remainder != 0)
            {
                SupressZeros = FALSE;
            }

            if (!SupressZeros)
            {
                String[k] = (UINT8) (ACPI_ASCII_ZERO + Remainder);
                k++;
            }
        }
        break;

    case 16:

        /* HexLength: 2 ascii hex chars per data byte */

        HexLength = ACPI_MUL_2 (DataWidth);
        for (i = 0, j = (HexLength-1); i < HexLength; i++, j--)
        {
            /* Get one hex digit, most significant digits first */

            String[k] = (UINT8) AcpiUtHexToAsciiChar (Integer, ACPI_MUL_4 (j));
            k++;
        }
        break;

    default:
        return (0);
    }

    /*
     * Since leading zeros are suppressed, we must check for the case where
     * the integer equals 0
     *
     * Finally, null terminate the string and return the length
     */
    if (!k)
    {
        String [0] = ACPI_ASCII_ZERO;
        k = 1;
    }

    String [k] = 0;
    return ((UINT32) k);
}
Esempio n. 4
0
ACPI_STATUS
AcpiUtStrtoul64 (
    char                    *String,
    UINT32                  Base,
    UINT64                  *RetInteger)
{
    UINT32                  ThisDigit = 0;
    UINT64                  ReturnValue = 0;
    UINT64                  Quotient;
    UINT64                  Dividend;
    UINT32                  ToIntegerOp = (Base == ACPI_ANY_BASE);
    UINT32                  Mode32 = (AcpiGbl_IntegerByteWidth == 4);
    UINT8                   ValidDigits = 0;
    UINT8                   SignOf0x = 0;
    UINT8                   Term = 0;


    ACPI_FUNCTION_TRACE_STR (UtStroul64, String);


    switch (Base)
    {
    case ACPI_ANY_BASE:
    case 16:

        break;

    default:

        /* Invalid Base */

        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    if (!String)
    {
        goto ErrorExit;
    }

    /* Skip over any white space in the buffer */

    while ((*String) && (ACPI_IS_SPACE (*String) || *String == '\t'))
    {
        String++;
    }

    if (ToIntegerOp)
    {
        /*
         * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'.
         * We need to determine if it is decimal or hexadecimal.
         */
        if ((*String == '0') && (ACPI_TOLOWER (*(String + 1)) == 'x'))
        {
            SignOf0x = 1;
            Base = 16;

            /* Skip over the leading '0x' */
            String += 2;
        }
        else
        {
            Base = 10;
        }
    }

    /* Any string left? Check that '0x' is not followed by white space. */

    if (!(*String) || ACPI_IS_SPACE (*String) || *String == '\t')
    {
        if (ToIntegerOp)
        {
            goto ErrorExit;
        }
        else
        {
            goto AllDone;
        }
    }

    /*
     * Perform a 32-bit or 64-bit conversion, depending upon the current
     * execution mode of the interpreter
     */
    Dividend = (Mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;

    /* Main loop: convert the string to a 32- or 64-bit integer */

    while (*String)
    {
        if (ACPI_IS_DIGIT (*String))
        {
            /* Convert ASCII 0-9 to Decimal value */

            ThisDigit = ((UINT8) *String) - '0';
        }
        else if (Base == 10)
        {
            /* Digit is out of range; possible in ToInteger case only */

            Term = 1;
        }
        else
        {
            ThisDigit = (UINT8) ACPI_TOUPPER (*String);
            if (ACPI_IS_XDIGIT ((char) ThisDigit))
            {
                /* Convert ASCII Hex char to value */

                ThisDigit = ThisDigit - 'A' + 10;
            }
            else
            {
                Term = 1;
            }
        }

        if (Term)
        {
            if (ToIntegerOp)
            {
                goto ErrorExit;
            }
            else
            {
                break;
            }
        }
        else if ((ValidDigits == 0) && (ThisDigit == 0) && !SignOf0x)
        {
            /* Skip zeros */
            String++;
            continue;
        }

        ValidDigits++;

        if (SignOf0x && ((ValidDigits > 16) || ((ValidDigits > 8) && Mode32)))
        {
            /*
             * This is ToInteger operation case.
             * No any restrictions for string-to-integer conversion,
             * see ACPI spec.
             */
            goto ErrorExit;
        }

        /* Divide the digit into the correct position */

        (void) AcpiUtShortDivide ((Dividend - (UINT64) ThisDigit),
                    Base, &Quotient, NULL);

        if (ReturnValue > Quotient)
        {
            if (ToIntegerOp)
            {
                goto ErrorExit;
            }
            else
            {
                break;
            }
        }

        ReturnValue *= Base;
        ReturnValue += ThisDigit;
        String++;
    }

    /* All done, normal exit */

AllDone:

    ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
        ACPI_FORMAT_UINT64 (ReturnValue)));

    *RetInteger = ReturnValue;
    return_ACPI_STATUS (AE_OK);


ErrorExit:
    /* Base was set/validated above */

    if (Base == 10)
    {
        return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT);
    }
    else
    {
        return_ACPI_STATUS (AE_BAD_HEX_CONSTANT);
    }
}
Esempio n. 5
0
ACPI_STATUS
AcpiExSystemMemorySpaceHandler (
    UINT32                  Function,
    ACPI_PHYSICAL_ADDRESS   Address,
    UINT32                  BitWidth,
    UINT64                  *Value,
    void                    *HandlerContext,
    void                    *RegionContext)
{
    ACPI_STATUS             Status = AE_OK;
    void                    *LogicalAddrPtr = NULL;
    ACPI_MEM_SPACE_CONTEXT  *MemInfo = RegionContext;
    UINT32                  Length;
    ACPI_SIZE               MapLength;
    ACPI_SIZE               PageBoundaryMapLength;
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
    UINT32                  Remainder;
#endif


    ACPI_FUNCTION_TRACE (ExSystemMemorySpaceHandler);


    /* Validate and translate the bit width */

    switch (BitWidth)
    {
    case 8:

        Length = 1;
        break;

    case 16:

        Length = 2;
        break;

    case 32:

        Length = 4;
        break;

    case 64:

        Length = 8;
        break;

    default:

        ACPI_ERROR ((AE_INFO, "Invalid SystemMemory width %u",
            BitWidth));
        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    }

#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
    /*
     * Hardware does not support non-aligned data transfers, we must verify
     * the request.
     */
    (void) AcpiUtShortDivide ((UINT64) Address, Length, NULL, &Remainder);
    if (Remainder != 0)
    {
        return_ACPI_STATUS (AE_AML_ALIGNMENT);
    }
#endif

    /*
     * Does the request fit into the cached memory mapping?
     * Is 1) Address below the current mapping? OR
     *    2) Address beyond the current mapping?
     */
    if ((Address < MemInfo->MappedPhysicalAddress) ||
        (((UINT64) Address + Length) >
            ((UINT64)
            MemInfo->MappedPhysicalAddress + MemInfo->MappedLength)))
    {
        /*
         * The request cannot be resolved by the current memory mapping;
         * Delete the existing mapping and create a new one.
         */
        if (MemInfo->MappedLength)
        {
            /* Valid mapping, delete it */

            AcpiOsUnmapMemory (MemInfo->MappedLogicalAddress,
                MemInfo->MappedLength);
        }

        /*
         * October 2009: Attempt to map from the requested address to the
         * end of the region. However, we will never map more than one
         * page, nor will we cross a page boundary.
         */
        MapLength = (ACPI_SIZE)
            ((MemInfo->Address + MemInfo->Length) - Address);

        /*
         * If mapping the entire remaining portion of the region will cross
         * a page boundary, just map up to the page boundary, do not cross.
         * On some systems, crossing a page boundary while mapping regions
         * can cause warnings if the pages have different attributes
         * due to resource management.
         *
         * This has the added benefit of constraining a single mapping to
         * one page, which is similar to the original code that used a 4k
         * maximum window.
         */
        PageBoundaryMapLength = (ACPI_SIZE)
            (ACPI_ROUND_UP (Address, ACPI_DEFAULT_PAGE_SIZE) - Address);
        if (PageBoundaryMapLength == 0)
        {
            PageBoundaryMapLength = ACPI_DEFAULT_PAGE_SIZE;
        }

        if (MapLength > PageBoundaryMapLength)
        {
            MapLength = PageBoundaryMapLength;
        }

        /* Create a new mapping starting at the address given */

        MemInfo->MappedLogicalAddress = AcpiOsMapMemory (Address, MapLength);
        if (!MemInfo->MappedLogicalAddress)
        {
            ACPI_ERROR ((AE_INFO,
                "Could not map memory at 0x%8.8X%8.8X, size %u",
                ACPI_FORMAT_UINT64 (Address), (UINT32) MapLength));
            MemInfo->MappedLength = 0;
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        /* Save the physical address and mapping size */

        MemInfo->MappedPhysicalAddress = Address;
        MemInfo->MappedLength = MapLength;
    }

    /*
     * Generate a logical pointer corresponding to the address we want to
     * access
     */
    LogicalAddrPtr = MemInfo->MappedLogicalAddress +
        ((UINT64) Address - (UINT64) MemInfo->MappedPhysicalAddress);

    ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
        "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
        BitWidth, Function, ACPI_FORMAT_UINT64 (Address)));

    /*
     * Perform the memory read or write
     *
     * Note: For machines that do not support non-aligned transfers, the target
     * address was checked for alignment above. We do not attempt to break the
     * transfer up into smaller (byte-size) chunks because the AML specifically
     * asked for a transfer width that the hardware may require.
     */
    switch (Function)
    {
    case ACPI_READ:

        *Value = 0;
        switch (BitWidth)
        {
        case 8:

            *Value = (UINT64) ACPI_GET8 (LogicalAddrPtr);
            break;

        case 16:

            *Value = (UINT64) ACPI_GET16 (LogicalAddrPtr);
            break;

        case 32:

            *Value = (UINT64) ACPI_GET32 (LogicalAddrPtr);
            break;

        case 64:

            *Value = (UINT64) ACPI_GET64 (LogicalAddrPtr);
            break;

        default:

            /* BitWidth was already validated */

            break;
        }
        break;

    case ACPI_WRITE:

        switch (BitWidth)
        {
        case 8:

            ACPI_SET8 (LogicalAddrPtr, *Value);
            break;

        case 16:

            ACPI_SET16 (LogicalAddrPtr, *Value);
            break;

        case 32:

            ACPI_SET32 (LogicalAddrPtr, *Value);
            break;

        case 64:

            ACPI_SET64 (LogicalAddrPtr, *Value);
            break;

        default:

            /* BitWidth was already validated */

            break;
        }
        break;

    default:

        Status = AE_BAD_PARAMETER;
        break;
    }

    return_ACPI_STATUS (Status);
}
ACPI_STATUS
AcpiExSystemMemorySpaceHandler (
    UINT32                  Function,
    ACPI_PHYSICAL_ADDRESS   Address,
    UINT32                  BitWidth,
    ACPI_INTEGER            *Value,
    void                    *HandlerContext,
    void                    *RegionContext)
{
    ACPI_STATUS             Status = AE_OK;
    void                    *LogicalAddrPtr = NULL;
    ACPI_MEM_SPACE_CONTEXT  *MemInfo = RegionContext;
    UINT32                  Length;
    ACPI_SIZE               WindowSize;
#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
    UINT32                  Remainder;
#endif


    ACPI_FUNCTION_TRACE (ExSystemMemorySpaceHandler);


    /* Validate and translate the bit width */

    switch (BitWidth)
    {
    case 8:
        Length = 1;
        break;

    case 16:
        Length = 2;
        break;

    case 32:
        Length = 4;
        break;

    case 64:
        Length = 8;
        break;

    default:
        ACPI_ERROR ((AE_INFO, "Invalid SystemMemory width %d",
            BitWidth));
        return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    }

#ifdef ACPI_MISALIGNMENT_NOT_SUPPORTED
    /*
     * Hardware does not support non-aligned data transfers, we must verify
     * the request.
     */
    (void) AcpiUtShortDivide ((ACPI_INTEGER) Address, Length, NULL, &Remainder);
    if (Remainder != 0)
    {
        return_ACPI_STATUS (AE_AML_ALIGNMENT);
    }
#endif

    /*
     * Does the request fit into the cached memory mapping?
     * Is 1) Address below the current mapping? OR
     *    2) Address beyond the current mapping?
     */
    if ((Address < MemInfo->MappedPhysicalAddress) ||
        (((ACPI_INTEGER) Address + Length) >
            ((ACPI_INTEGER)
            MemInfo->MappedPhysicalAddress + MemInfo->MappedLength)))
    {
        /*
         * The request cannot be resolved by the current memory mapping;
         * Delete the existing mapping and create a new one.
         */
        if (MemInfo->MappedLength)
        {
            /* Valid mapping, delete it */

            AcpiOsUnmapMemory (MemInfo->MappedLogicalAddress,
                MemInfo->MappedLength);
        }

        /*
         * Don't attempt to map memory beyond the end of the region, and
         * constrain the maximum mapping size to something reasonable.
         */
        WindowSize = (ACPI_SIZE)
            ((MemInfo->Address + MemInfo->Length) - Address);

        if (WindowSize > ACPI_SYSMEM_REGION_WINDOW_SIZE)
        {
            WindowSize = ACPI_SYSMEM_REGION_WINDOW_SIZE;
        }

        /* Create a new mapping starting at the address given */

        MemInfo->MappedLogicalAddress = AcpiOsMapMemory (
            (ACPI_PHYSICAL_ADDRESS) Address, WindowSize);
        if (!MemInfo->MappedLogicalAddress)
        {
            ACPI_ERROR ((AE_INFO,
                "Could not map memory at %8.8X%8.8X, size %X",
                ACPI_FORMAT_NATIVE_UINT (Address), (UINT32) WindowSize));
            MemInfo->MappedLength = 0;
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        /* Save the physical address and mapping size */

        MemInfo->MappedPhysicalAddress = Address;
        MemInfo->MappedLength = WindowSize;
    }

    /*
     * Generate a logical pointer corresponding to the address we want to
     * access
     */
    LogicalAddrPtr = MemInfo->MappedLogicalAddress +
        ((ACPI_INTEGER) Address - (ACPI_INTEGER) MemInfo->MappedPhysicalAddress);

    ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
        "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
        BitWidth, Function, ACPI_FORMAT_NATIVE_UINT (Address)));

    /*
     * Perform the memory read or write
     *
     * Note: For machines that do not support non-aligned transfers, the target
     * address was checked for alignment above.  We do not attempt to break the
     * transfer up into smaller (byte-size) chunks because the AML specifically
     * asked for a transfer width that the hardware may require.
     */
    switch (Function)
    {
    case ACPI_READ:

        *Value = 0;
        switch (BitWidth)
        {
        case 8:
            *Value = (ACPI_INTEGER) ACPI_GET8 (LogicalAddrPtr);
            break;

        case 16:
            *Value = (ACPI_INTEGER) ACPI_GET16 (LogicalAddrPtr);
            break;

        case 32:
            *Value = (ACPI_INTEGER) ACPI_GET32 (LogicalAddrPtr);
            break;

        case 64:
            *Value = (ACPI_INTEGER) ACPI_GET64 (LogicalAddrPtr);
            break;

        default:
            /* BitWidth was already validated */
            break;
        }
        break;

    case ACPI_WRITE:

        switch (BitWidth)
        {
        case 8:
            ACPI_SET8 (LogicalAddrPtr) = (UINT8) *Value;
            break;

        case 16:
            ACPI_SET16 (LogicalAddrPtr) = (UINT16) *Value;
            break;

        case 32:
            ACPI_SET32 ( LogicalAddrPtr) = (UINT32) *Value;
            break;

        case 64:
            ACPI_SET64 (LogicalAddrPtr) = (UINT64) *Value;
            break;

        default:
            /* BitWidth was already validated */
            break;
        }
        break;

    default:
        Status = AE_BAD_PARAMETER;
        break;
    }

    return_ACPI_STATUS (Status);
}
Esempio n. 7
0
ACPI_STATUS
AcpiGetTimerDuration (
    UINT32                  StartTicks,
    UINT32                  EndTicks,
    UINT32                  *TimeElapsed)
{
    UINT32                  DeltaTicks = 0;
    UINT64_OVERLAY          NormalizedTicks;
    ACPI_STATUS             Status;
    ACPI_INTEGER            OutQuotient;


    ACPI_FUNCTION_TRACE ("AcpiGetTimerDuration");


    if (!TimeElapsed)
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    /*
     * Compute Tick Delta:
     * -------------------
     * Handle (max one) timer rollovers on 24- versus 32-bit timers.
     */
    if (StartTicks < EndTicks)
    {
        DeltaTicks = EndTicks - StartTicks;
    }
    else if (StartTicks > EndTicks)
    {
        if (0 == AcpiGbl_FADT->TmrValExt)
        {
            /* 24-bit Timer */

            DeltaTicks = (((0x00FFFFFF - StartTicks) + EndTicks) & 0x00FFFFFF);
        }
        else
        {
            /* 32-bit Timer */

            DeltaTicks = (0xFFFFFFFF - StartTicks) + EndTicks;
        }
    }
    else
    {
        *TimeElapsed = 0;
        return_ACPI_STATUS (AE_OK);
    }

    /*
     * Compute Duration:
     * -----------------
     *
     * Requires a 64-bit divide:
     *
     * TimeElapsed = (DeltaTicks * 1000000) / PM_TIMER_FREQUENCY;
     */
    NormalizedTicks.Full = ((UINT64) DeltaTicks) * 1000000;

    Status = AcpiUtShortDivide (&NormalizedTicks.Full, PM_TIMER_FREQUENCY,
                                    &OutQuotient, NULL);

    *TimeElapsed = (UINT32) OutQuotient;
    return_ACPI_STATUS (Status);
}
Esempio n. 8
0
ACPI_STATUS
AcpiUtStrtoul64 (
    char                    *String,
    UINT32                  Base,
    ACPI_INTEGER            *RetInteger)
{
    UINT32                  Index;
    ACPI_INTEGER            ReturnValue = 0;
    ACPI_STATUS             Status = AE_OK;
    ACPI_INTEGER            Dividend;
    ACPI_INTEGER            Quotient;


    *RetInteger = 0;

    switch (Base)
    {
    case 0:
    case 8:
    case 10:
    case 16:
        break;

    default:
        /*
         * The specified Base parameter is not in the domain of
         * this function:
         */
        return (AE_BAD_PARAMETER);
    }

    /*
     * skip over any white space in the buffer:
     */
    while (ACPI_IS_SPACE (*String) || *String == '\t')
    {
        ++String;
    }

    /*
     * If the input parameter Base is zero, then we need to
     * determine if it is octal, decimal, or hexadecimal:
     */
    if (Base == 0)
    {
        if (*String == '0')
        {
            if (ACPI_TOLOWER (*(++String)) == 'x')
            {
                Base = 16;
                ++String;
            }
            else
            {
                Base = 8;
            }
        }
        else
        {
            Base = 10;
        }
    }

    /*
     * For octal and hexadecimal bases, skip over the leading
     * 0 or 0x, if they are present.
     */
    if (Base == 8 && *String == '0')
    {
        String++;
    }

    if (Base == 16 &&
        *String == '0' &&
        ACPI_TOLOWER (*(++String)) == 'x')
    {
        String++;
    }

    /* Main loop: convert the string to an unsigned long */

    while (*String)
    {
        if (ACPI_IS_DIGIT (*String))
        {
            Index = ((UINT8) *String) - '0';
        }
        else
        {
            Index = (UINT8) ACPI_TOUPPER (*String);
            if (ACPI_IS_UPPER ((char) Index))
            {
                Index = Index - 'A' + 10;
            }
            else
            {
                goto ErrorExit;
            }
        }

        if (Index >= Base)
        {
            goto ErrorExit;
        }

        /* Check to see if value is out of range: */

        Dividend = ACPI_INTEGER_MAX - (ACPI_INTEGER) Index;
        (void) AcpiUtShortDivide (&Dividend, Base, &Quotient, NULL);
        if (ReturnValue > Quotient)
        {
            goto ErrorExit;
        }

        ReturnValue *= Base;
        ReturnValue += Index;
        ++String;
    }

    *RetInteger = ReturnValue;
    return (Status);


ErrorExit:
    switch (Base)
    {
    case 8:
        Status = AE_BAD_OCTAL_CONSTANT;
        break;

    case 10:
        Status = AE_BAD_DECIMAL_CONSTANT;
        break;

    case 16:
        Status = AE_BAD_HEX_CONSTANT;
        break;

    default:
        /* Base validated above */
        break;
    }

    return (Status);
}