Skip to content

Commit

Permalink
Hardware: Enable 64-bit firmware waking vector for selected FACS.
Browse files Browse the repository at this point in the history
The root cause of the reported bug might be one of the followings:
1. BIOS may favor the 64-bit firmware waking vector address when the
   version of the FACS is greater than 0 and Linux currently only supports
   resuming from the real mode, so the 64-bit firmware waking vector has
   never been set and might be invalid to BIOS while the commit enables
   higher version FACS.
2. BIOS may favor the FACS reported via the "FIRMWARE_CTRL" field in the
   FADT while the commit doesn't set the firmware waking vector address of
   the FACS reported by "FIRMWARE_CTRL", it only sets the firware waking
   vector address of the FACS reported by "X_FIRMWARE_CTRL".

This patch excludes the cases that can trigger the bugs caused by the root
cause 1.

ACPI specification says:
A. 32-bit FACS address (FIRMWARE_CTRL field in FADT):
   Physical memory address of the FACS, where OSPM and firmware exchange
   control information.
   If the X_FIRMWARE_CTRL field contains a non zero value then this field
   must be zero.
   A zero value indicates that no FACS is specified by this field.
B. 64-bit FACS address (X_FIRMWARE_CTRL field in FADT):
   64bit physical memory address of the FACS.
   This field is used when the physical address of the FACS is above 4GB.
   If the FIRMWARE_CTRL field contains a non zero value then this field
   must be zero.
   A zero value indicates that no FACS is specified by this field.
Thus the 32bit and 64bit firmware waking vector should indicate completely
different resuming environment - real mode (1MB addressable) and non real
mode (4GB+ addressable) and currently Linux only supports resuming from
real mode.

This patch enables 64-bit firmware waking vector for selected FACS via
AcpiSetFirmwareWakingVector() so that it's up to OSPMs to determine which
resuming mode should be used by BIOS and ACPICA changes won't trigger the
bugs caused by the root cause 1. For example, Linux can pass
PhysicalAddress64=0 as the parameter of AcpiSetFirmwareWakingVector() to
indicate no 64bit waking vector support. Lv Zheng.

Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=74021
Reported-and-tested-by: Oswald Buddenhagen <ossi@kde.org>
Signed-off-by: Lv Zheng <lv.zheng@intel.com>
  • Loading branch information
Lv Zheng committed May 30, 2014
1 parent 9125f79 commit 7aa598d
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 57 deletions.
68 changes: 19 additions & 49 deletions source/components/hardware/hwxfsleep.c
Expand Up @@ -149,7 +149,6 @@ static ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] =
/*
* These functions are removed for the ACPI_REDUCED_HARDWARE case:
* AcpiSetFirmwareWakingVector
* AcpiSetFirmwareWakingVector64
* AcpiEnterSleepStateS4bios
*/

Expand All @@ -159,17 +158,20 @@ static ACPI_SLEEP_FUNCTIONS AcpiSleepDispatch[] =
* FUNCTION: AcpiSetFirmwareWakingVector
*
* PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode
* entry point.
* entry point
* PhysicalAddress64 - 64-bit physical address of ACPI protected
* entry point
*
* RETURN: Status
*
* DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS
* DESCRIPTION: Sets the FirmwareWakingVector fields of the FACS
*
******************************************************************************/

ACPI_STATUS
AcpiSetFirmwareWakingVector (
UINT32 PhysicalAddress)
ACPI_PHYSICAL_ADDRESS PhysicalAddress,
ACPI_PHYSICAL_ADDRESS PhysicalAddress64)
{
ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);

Expand All @@ -184,60 +186,28 @@ AcpiSetFirmwareWakingVector (

/* Set the 32-bit vector */

AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress;
AcpiGbl_FACS->FirmwareWakingVector = (UINT32) PhysicalAddress;

/* Clear the 64-bit vector if it exists */

if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1))
if (AcpiGbl_FACS->Length > 32)
{
AcpiGbl_FACS->XFirmwareWakingVector = 0;
}

return_ACPI_STATUS (AE_OK);
}

ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)


#if ACPI_MACHINE_WIDTH == 64
/*******************************************************************************
*
* FUNCTION: AcpiSetFirmwareWakingVector64
*
* PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected
* mode entry point.
*
* RETURN: Status
*
* DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if
* it exists in the table. This function is intended for use with
* 64-bit host operating systems.
*
******************************************************************************/

ACPI_STATUS
AcpiSetFirmwareWakingVector64 (
UINT64 PhysicalAddress)
{
ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64);

if (AcpiGbl_FACS->Version >= 1)
{
/* Set the 64-bit vector */

/* Determine if the 64-bit vector actually exists */
AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress64;
}
else
{
/* Clear the 64-bit vector if it exists */

if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1))
{
return_ACPI_STATUS (AE_NOT_EXIST);
AcpiGbl_FACS->XFirmwareWakingVector = 0;
}
}

/* Clear 32-bit vector, set the 64-bit X_ vector */

AcpiGbl_FACS->FirmwareWakingVector = 0;
AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress;
return_ACPI_STATUS (AE_OK);
}

ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64)
#endif
ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)


/*******************************************************************************
Expand Down
10 changes: 2 additions & 8 deletions source/include/acpixf.h
Expand Up @@ -1091,14 +1091,8 @@ AcpiLeaveSleepState (
ACPI_HW_DEPENDENT_RETURN_STATUS (
ACPI_STATUS
AcpiSetFirmwareWakingVector (
UINT32 PhysicalAddress))

#if ACPI_MACHINE_WIDTH == 64
ACPI_HW_DEPENDENT_RETURN_STATUS (
ACPI_STATUS
AcpiSetFirmwareWakingVector64 (
UINT64 PhysicalAddress))
#endif
ACPI_PHYSICAL_ADDRESS PhysicalAddress,
ACPI_PHYSICAL_ADDRESS PhysicalAddress64))


/*
Expand Down

0 comments on commit 7aa598d

Please sign in to comment.