cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

evglock.c (8944B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: evglock - Global Lock support
      5 *
      6 * Copyright (C) 2000 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10#include <acpi/acpi.h>
     11#include "accommon.h"
     12#include "acevents.h"
     13#include "acinterp.h"
     14
     15#define _COMPONENT          ACPI_EVENTS
     16ACPI_MODULE_NAME("evglock")
     17#if (!ACPI_REDUCED_HARDWARE)	/* Entire module */
     18/* Local prototypes */
     19static u32 acpi_ev_global_lock_handler(void *context);
     20
     21/*******************************************************************************
     22 *
     23 * FUNCTION:    acpi_ev_init_global_lock_handler
     24 *
     25 * PARAMETERS:  None
     26 *
     27 * RETURN:      Status
     28 *
     29 * DESCRIPTION: Install a handler for the global lock release event
     30 *
     31 ******************************************************************************/
     32
     33acpi_status acpi_ev_init_global_lock_handler(void)
     34{
     35	acpi_status status;
     36
     37	ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
     38
     39	/* If Hardware Reduced flag is set, there is no global lock */
     40
     41	if (acpi_gbl_reduced_hardware) {
     42		return_ACPI_STATUS(AE_OK);
     43	}
     44
     45	/* Attempt installation of the global lock handler */
     46
     47	status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
     48						  acpi_ev_global_lock_handler,
     49						  NULL);
     50
     51	/*
     52	 * If the global lock does not exist on this platform, the attempt to
     53	 * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
     54	 * Map to AE_OK, but mark global lock as not present. Any attempt to
     55	 * actually use the global lock will be flagged with an error.
     56	 */
     57	acpi_gbl_global_lock_present = FALSE;
     58	if (status == AE_NO_HARDWARE_RESPONSE) {
     59		ACPI_ERROR((AE_INFO,
     60			    "No response from Global Lock hardware, disabling lock"));
     61
     62		return_ACPI_STATUS(AE_OK);
     63	}
     64
     65	status = acpi_os_create_lock(&acpi_gbl_global_lock_pending_lock);
     66	if (ACPI_FAILURE(status)) {
     67		return_ACPI_STATUS(status);
     68	}
     69
     70	acpi_gbl_global_lock_pending = FALSE;
     71	acpi_gbl_global_lock_present = TRUE;
     72	return_ACPI_STATUS(status);
     73}
     74
     75/*******************************************************************************
     76 *
     77 * FUNCTION:    acpi_ev_remove_global_lock_handler
     78 *
     79 * PARAMETERS:  None
     80 *
     81 * RETURN:      Status
     82 *
     83 * DESCRIPTION: Remove the handler for the Global Lock
     84 *
     85 ******************************************************************************/
     86
     87acpi_status acpi_ev_remove_global_lock_handler(void)
     88{
     89	acpi_status status;
     90
     91	ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
     92
     93	acpi_gbl_global_lock_present = FALSE;
     94	status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
     95						 acpi_ev_global_lock_handler);
     96
     97	acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
     98	return_ACPI_STATUS(status);
     99}
    100
    101/*******************************************************************************
    102 *
    103 * FUNCTION:    acpi_ev_global_lock_handler
    104 *
    105 * PARAMETERS:  context         - From thread interface, not used
    106 *
    107 * RETURN:      ACPI_INTERRUPT_HANDLED
    108 *
    109 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
    110 *              release interrupt occurs. If there is actually a pending
    111 *              request for the lock, signal the waiting thread.
    112 *
    113 ******************************************************************************/
    114
    115static u32 acpi_ev_global_lock_handler(void *context)
    116{
    117	acpi_status status;
    118	acpi_cpu_flags flags;
    119
    120	flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
    121
    122	/*
    123	 * If a request for the global lock is not actually pending,
    124	 * we are done. This handles "spurious" global lock interrupts
    125	 * which are possible (and have been seen) with bad BIOSs.
    126	 */
    127	if (!acpi_gbl_global_lock_pending) {
    128		goto cleanup_and_exit;
    129	}
    130
    131	/*
    132	 * Send a unit to the global lock semaphore. The actual acquisition
    133	 * of the global lock will be performed by the waiting thread.
    134	 */
    135	status = acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore, 1);
    136	if (ACPI_FAILURE(status)) {
    137		ACPI_ERROR((AE_INFO, "Could not signal Global Lock semaphore"));
    138	}
    139
    140	acpi_gbl_global_lock_pending = FALSE;
    141
    142cleanup_and_exit:
    143
    144	acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
    145	return (ACPI_INTERRUPT_HANDLED);
    146}
    147
    148/******************************************************************************
    149 *
    150 * FUNCTION:    acpi_ev_acquire_global_lock
    151 *
    152 * PARAMETERS:  timeout         - Max time to wait for the lock, in millisec.
    153 *
    154 * RETURN:      Status
    155 *
    156 * DESCRIPTION: Attempt to gain ownership of the Global Lock.
    157 *
    158 * MUTEX:       Interpreter must be locked
    159 *
    160 * Note: The original implementation allowed multiple threads to "acquire" the
    161 * Global Lock, and the OS would hold the lock until the last thread had
    162 * released it. However, this could potentially starve the BIOS out of the
    163 * lock, especially in the case where there is a tight handshake between the
    164 * Embedded Controller driver and the BIOS. Therefore, this implementation
    165 * allows only one thread to acquire the HW Global Lock at a time, and makes
    166 * the global lock appear as a standard mutex on the OS side.
    167 *
    168 *****************************************************************************/
    169
    170acpi_status acpi_ev_acquire_global_lock(u16 timeout)
    171{
    172	acpi_cpu_flags flags;
    173	acpi_status status;
    174	u8 acquired = FALSE;
    175
    176	ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
    177
    178	/*
    179	 * Only one thread can acquire the GL at a time, the global_lock_mutex
    180	 * enforces this. This interface releases the interpreter if we must wait.
    181	 */
    182	status =
    183	    acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex->mutex.
    184				      os_mutex, timeout);
    185	if (ACPI_FAILURE(status)) {
    186		return_ACPI_STATUS(status);
    187	}
    188
    189	/*
    190	 * Update the global lock handle and check for wraparound. The handle is
    191	 * only used for the external global lock interfaces, but it is updated
    192	 * here to properly handle the case where a single thread may acquire the
    193	 * lock via both the AML and the acpi_acquire_global_lock interfaces. The
    194	 * handle is therefore updated on the first acquire from a given thread
    195	 * regardless of where the acquisition request originated.
    196	 */
    197	acpi_gbl_global_lock_handle++;
    198	if (acpi_gbl_global_lock_handle == 0) {
    199		acpi_gbl_global_lock_handle = 1;
    200	}
    201
    202	/*
    203	 * Make sure that a global lock actually exists. If not, just
    204	 * treat the lock as a standard mutex.
    205	 */
    206	if (!acpi_gbl_global_lock_present) {
    207		acpi_gbl_global_lock_acquired = TRUE;
    208		return_ACPI_STATUS(AE_OK);
    209	}
    210
    211	flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
    212
    213	do {
    214
    215		/* Attempt to acquire the actual hardware lock */
    216
    217		ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired);
    218		if (acquired) {
    219			acpi_gbl_global_lock_acquired = TRUE;
    220			ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
    221					  "Acquired hardware Global Lock\n"));
    222			break;
    223		}
    224
    225		/*
    226		 * Did not get the lock. The pending bit was set above, and
    227		 * we must now wait until we receive the global lock
    228		 * released interrupt.
    229		 */
    230		acpi_gbl_global_lock_pending = TRUE;
    231		acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
    232
    233		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
    234				  "Waiting for hardware Global Lock\n"));
    235
    236		/*
    237		 * Wait for handshake with the global lock interrupt handler.
    238		 * This interface releases the interpreter if we must wait.
    239		 */
    240		status =
    241		    acpi_ex_system_wait_semaphore
    242		    (acpi_gbl_global_lock_semaphore, ACPI_WAIT_FOREVER);
    243
    244		flags = acpi_os_acquire_lock(acpi_gbl_global_lock_pending_lock);
    245
    246	} while (ACPI_SUCCESS(status));
    247
    248	acpi_gbl_global_lock_pending = FALSE;
    249	acpi_os_release_lock(acpi_gbl_global_lock_pending_lock, flags);
    250
    251	return_ACPI_STATUS(status);
    252}
    253
    254/*******************************************************************************
    255 *
    256 * FUNCTION:    acpi_ev_release_global_lock
    257 *
    258 * PARAMETERS:  None
    259 *
    260 * RETURN:      Status
    261 *
    262 * DESCRIPTION: Releases ownership of the Global Lock.
    263 *
    264 ******************************************************************************/
    265
    266acpi_status acpi_ev_release_global_lock(void)
    267{
    268	u8 pending = FALSE;
    269	acpi_status status = AE_OK;
    270
    271	ACPI_FUNCTION_TRACE(ev_release_global_lock);
    272
    273	/* Lock must be already acquired */
    274
    275	if (!acpi_gbl_global_lock_acquired) {
    276		ACPI_WARNING((AE_INFO,
    277			      "Cannot release the ACPI Global Lock, it has not been acquired"));
    278		return_ACPI_STATUS(AE_NOT_ACQUIRED);
    279	}
    280
    281	if (acpi_gbl_global_lock_present) {
    282
    283		/* Allow any thread to release the lock */
    284
    285		ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending);
    286
    287		/*
    288		 * If the pending bit was set, we must write GBL_RLS to the control
    289		 * register
    290		 */
    291		if (pending) {
    292			status =
    293			    acpi_write_bit_register
    294			    (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
    295			     ACPI_ENABLE_EVENT);
    296		}
    297
    298		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
    299				  "Released hardware Global Lock\n"));
    300	}
    301
    302	acpi_gbl_global_lock_acquired = FALSE;
    303
    304	/* Release the local GL mutex */
    305
    306	acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
    307	return_ACPI_STATUS(status);
    308}
    309
    310#endif				/* !ACPI_REDUCED_HARDWARE */