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

console.c (3581B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Functions for saving/restoring console.
      4 *
      5 * Originally from swsusp.
      6 */
      7
      8#include <linux/console.h>
      9#include <linux/vt_kern.h>
     10#include <linux/kbd_kern.h>
     11#include <linux/vt.h>
     12#include <linux/module.h>
     13#include <linux/slab.h>
     14#include "power.h"
     15
     16#define SUSPEND_CONSOLE	(MAX_NR_CONSOLES-1)
     17
     18static int orig_fgconsole, orig_kmsg;
     19
     20static DEFINE_MUTEX(vt_switch_mutex);
     21
     22struct pm_vt_switch {
     23	struct list_head head;
     24	struct device *dev;
     25	bool required;
     26};
     27
     28static LIST_HEAD(pm_vt_switch_list);
     29
     30
     31/**
     32 * pm_vt_switch_required - indicate VT switch at suspend requirements
     33 * @dev: device
     34 * @required: if true, caller needs VT switch at suspend/resume time
     35 *
     36 * The different console drivers may or may not require VT switches across
     37 * suspend/resume, depending on how they handle restoring video state and
     38 * what may be running.
     39 *
     40 * Drivers can indicate support for switchless suspend/resume, which can
     41 * save time and flicker, by using this routine and passing 'false' as
     42 * the argument.  If any loaded driver needs VT switching, or the
     43 * no_console_suspend argument has been passed on the command line, VT
     44 * switches will occur.
     45 */
     46void pm_vt_switch_required(struct device *dev, bool required)
     47{
     48	struct pm_vt_switch *entry, *tmp;
     49
     50	mutex_lock(&vt_switch_mutex);
     51	list_for_each_entry(tmp, &pm_vt_switch_list, head) {
     52		if (tmp->dev == dev) {
     53			/* already registered, update requirement */
     54			tmp->required = required;
     55			goto out;
     56		}
     57	}
     58
     59	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
     60	if (!entry)
     61		goto out;
     62
     63	entry->required = required;
     64	entry->dev = dev;
     65
     66	list_add(&entry->head, &pm_vt_switch_list);
     67out:
     68	mutex_unlock(&vt_switch_mutex);
     69}
     70EXPORT_SYMBOL(pm_vt_switch_required);
     71
     72/**
     73 * pm_vt_switch_unregister - stop tracking a device's VT switching needs
     74 * @dev: device
     75 *
     76 * Remove @dev from the vt switch list.
     77 */
     78void pm_vt_switch_unregister(struct device *dev)
     79{
     80	struct pm_vt_switch *tmp;
     81
     82	mutex_lock(&vt_switch_mutex);
     83	list_for_each_entry(tmp, &pm_vt_switch_list, head) {
     84		if (tmp->dev == dev) {
     85			list_del(&tmp->head);
     86			kfree(tmp);
     87			break;
     88		}
     89	}
     90	mutex_unlock(&vt_switch_mutex);
     91}
     92EXPORT_SYMBOL(pm_vt_switch_unregister);
     93
     94/*
     95 * There are three cases when a VT switch on suspend/resume are required:
     96 *   1) no driver has indicated a requirement one way or another, so preserve
     97 *      the old behavior
     98 *   2) console suspend is disabled, we want to see debug messages across
     99 *      suspend/resume
    100 *   3) any registered driver indicates it needs a VT switch
    101 *
    102 * If none of these conditions is present, meaning we have at least one driver
    103 * that doesn't need the switch, and none that do, we can avoid it to make
    104 * resume look a little prettier (and suspend too, but that's usually hidden,
    105 * e.g. when closing the lid on a laptop).
    106 */
    107static bool pm_vt_switch(void)
    108{
    109	struct pm_vt_switch *entry;
    110	bool ret = true;
    111
    112	mutex_lock(&vt_switch_mutex);
    113	if (list_empty(&pm_vt_switch_list))
    114		goto out;
    115
    116	if (!console_suspend_enabled)
    117		goto out;
    118
    119	list_for_each_entry(entry, &pm_vt_switch_list, head) {
    120		if (entry->required)
    121			goto out;
    122	}
    123
    124	ret = false;
    125out:
    126	mutex_unlock(&vt_switch_mutex);
    127	return ret;
    128}
    129
    130void pm_prepare_console(void)
    131{
    132	if (!pm_vt_switch())
    133		return;
    134
    135	orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1);
    136	if (orig_fgconsole < 0)
    137		return;
    138
    139	orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE);
    140	return;
    141}
    142
    143void pm_restore_console(void)
    144{
    145	if (!pm_vt_switch())
    146		return;
    147
    148	if (orig_fgconsole >= 0) {
    149		vt_move_to_console(orig_fgconsole, 0);
    150		vt_kmsg_redirect(orig_kmsg);
    151	}
    152}