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

user.c (9590B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * linux/kernel/power/user.c
      4 *
      5 * This file provides the user space interface for software suspend/resume.
      6 *
      7 * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
      8 */
      9
     10#include <linux/suspend.h>
     11#include <linux/reboot.h>
     12#include <linux/string.h>
     13#include <linux/device.h>
     14#include <linux/miscdevice.h>
     15#include <linux/mm.h>
     16#include <linux/swap.h>
     17#include <linux/swapops.h>
     18#include <linux/pm.h>
     19#include <linux/fs.h>
     20#include <linux/compat.h>
     21#include <linux/console.h>
     22#include <linux/cpu.h>
     23#include <linux/freezer.h>
     24
     25#include <linux/uaccess.h>
     26
     27#include "power.h"
     28
     29
     30static struct snapshot_data {
     31	struct snapshot_handle handle;
     32	int swap;
     33	int mode;
     34	bool frozen;
     35	bool ready;
     36	bool platform_support;
     37	bool free_bitmaps;
     38	dev_t dev;
     39} snapshot_state;
     40
     41int is_hibernate_resume_dev(dev_t dev)
     42{
     43	return hibernation_available() && snapshot_state.dev == dev;
     44}
     45
     46static int snapshot_open(struct inode *inode, struct file *filp)
     47{
     48	struct snapshot_data *data;
     49	int error;
     50
     51	if (!hibernation_available())
     52		return -EPERM;
     53
     54	lock_system_sleep();
     55
     56	if (!hibernate_acquire()) {
     57		error = -EBUSY;
     58		goto Unlock;
     59	}
     60
     61	if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
     62		hibernate_release();
     63		error = -ENOSYS;
     64		goto Unlock;
     65	}
     66	nonseekable_open(inode, filp);
     67	data = &snapshot_state;
     68	filp->private_data = data;
     69	memset(&data->handle, 0, sizeof(struct snapshot_handle));
     70	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
     71		/* Hibernating.  The image device should be accessible. */
     72		data->swap = swap_type_of(swsusp_resume_device, 0);
     73		data->mode = O_RDONLY;
     74		data->free_bitmaps = false;
     75		error = pm_notifier_call_chain_robust(PM_HIBERNATION_PREPARE, PM_POST_HIBERNATION);
     76	} else {
     77		/*
     78		 * Resuming.  We may need to wait for the image device to
     79		 * appear.
     80		 */
     81		wait_for_device_probe();
     82
     83		data->swap = -1;
     84		data->mode = O_WRONLY;
     85		error = pm_notifier_call_chain_robust(PM_RESTORE_PREPARE, PM_POST_RESTORE);
     86		if (!error) {
     87			error = create_basic_memory_bitmaps();
     88			data->free_bitmaps = !error;
     89		}
     90	}
     91	if (error)
     92		hibernate_release();
     93
     94	data->frozen = false;
     95	data->ready = false;
     96	data->platform_support = false;
     97	data->dev = 0;
     98
     99 Unlock:
    100	unlock_system_sleep();
    101
    102	return error;
    103}
    104
    105static int snapshot_release(struct inode *inode, struct file *filp)
    106{
    107	struct snapshot_data *data;
    108
    109	lock_system_sleep();
    110
    111	swsusp_free();
    112	data = filp->private_data;
    113	data->dev = 0;
    114	free_all_swap_pages(data->swap);
    115	if (data->frozen) {
    116		pm_restore_gfp_mask();
    117		free_basic_memory_bitmaps();
    118		thaw_processes();
    119	} else if (data->free_bitmaps) {
    120		free_basic_memory_bitmaps();
    121	}
    122	pm_notifier_call_chain(data->mode == O_RDONLY ?
    123			PM_POST_HIBERNATION : PM_POST_RESTORE);
    124	hibernate_release();
    125
    126	unlock_system_sleep();
    127
    128	return 0;
    129}
    130
    131static ssize_t snapshot_read(struct file *filp, char __user *buf,
    132                             size_t count, loff_t *offp)
    133{
    134	struct snapshot_data *data;
    135	ssize_t res;
    136	loff_t pg_offp = *offp & ~PAGE_MASK;
    137
    138	lock_system_sleep();
    139
    140	data = filp->private_data;
    141	if (!data->ready) {
    142		res = -ENODATA;
    143		goto Unlock;
    144	}
    145	if (!pg_offp) { /* on page boundary? */
    146		res = snapshot_read_next(&data->handle);
    147		if (res <= 0)
    148			goto Unlock;
    149	} else {
    150		res = PAGE_SIZE - pg_offp;
    151	}
    152
    153	res = simple_read_from_buffer(buf, count, &pg_offp,
    154			data_of(data->handle), res);
    155	if (res > 0)
    156		*offp += res;
    157
    158 Unlock:
    159	unlock_system_sleep();
    160
    161	return res;
    162}
    163
    164static ssize_t snapshot_write(struct file *filp, const char __user *buf,
    165                              size_t count, loff_t *offp)
    166{
    167	struct snapshot_data *data;
    168	ssize_t res;
    169	loff_t pg_offp = *offp & ~PAGE_MASK;
    170
    171	lock_system_sleep();
    172
    173	data = filp->private_data;
    174
    175	if (!pg_offp) {
    176		res = snapshot_write_next(&data->handle);
    177		if (res <= 0)
    178			goto unlock;
    179	} else {
    180		res = PAGE_SIZE;
    181	}
    182
    183	if (!data_of(data->handle)) {
    184		res = -EINVAL;
    185		goto unlock;
    186	}
    187
    188	res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
    189			buf, count);
    190	if (res > 0)
    191		*offp += res;
    192unlock:
    193	unlock_system_sleep();
    194
    195	return res;
    196}
    197
    198struct compat_resume_swap_area {
    199	compat_loff_t offset;
    200	u32 dev;
    201} __packed;
    202
    203static int snapshot_set_swap_area(struct snapshot_data *data,
    204		void __user *argp)
    205{
    206	sector_t offset;
    207	dev_t swdev;
    208
    209	if (swsusp_swap_in_use())
    210		return -EPERM;
    211
    212	if (in_compat_syscall()) {
    213		struct compat_resume_swap_area swap_area;
    214
    215		if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
    216			return -EFAULT;
    217		swdev = new_decode_dev(swap_area.dev);
    218		offset = swap_area.offset;
    219	} else {
    220		struct resume_swap_area swap_area;
    221
    222		if (copy_from_user(&swap_area, argp, sizeof(swap_area)))
    223			return -EFAULT;
    224		swdev = new_decode_dev(swap_area.dev);
    225		offset = swap_area.offset;
    226	}
    227
    228	/*
    229	 * User space encodes device types as two-byte values,
    230	 * so we need to recode them
    231	 */
    232	data->swap = swap_type_of(swdev, offset);
    233	if (data->swap < 0)
    234		return swdev ? -ENODEV : -EINVAL;
    235	data->dev = swdev;
    236	return 0;
    237}
    238
    239static long snapshot_ioctl(struct file *filp, unsigned int cmd,
    240							unsigned long arg)
    241{
    242	int error = 0;
    243	struct snapshot_data *data;
    244	loff_t size;
    245	sector_t offset;
    246
    247	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
    248		return -ENOTTY;
    249	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
    250		return -ENOTTY;
    251	if (!capable(CAP_SYS_ADMIN))
    252		return -EPERM;
    253
    254	if (!mutex_trylock(&system_transition_mutex))
    255		return -EBUSY;
    256
    257	lock_device_hotplug();
    258	data = filp->private_data;
    259
    260	switch (cmd) {
    261
    262	case SNAPSHOT_FREEZE:
    263		if (data->frozen)
    264			break;
    265
    266		ksys_sync_helper();
    267
    268		error = freeze_processes();
    269		if (error)
    270			break;
    271
    272		error = create_basic_memory_bitmaps();
    273		if (error)
    274			thaw_processes();
    275		else
    276			data->frozen = true;
    277
    278		break;
    279
    280	case SNAPSHOT_UNFREEZE:
    281		if (!data->frozen || data->ready)
    282			break;
    283		pm_restore_gfp_mask();
    284		free_basic_memory_bitmaps();
    285		data->free_bitmaps = false;
    286		thaw_processes();
    287		data->frozen = false;
    288		break;
    289
    290	case SNAPSHOT_CREATE_IMAGE:
    291		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
    292			error = -EPERM;
    293			break;
    294		}
    295		pm_restore_gfp_mask();
    296		error = hibernation_snapshot(data->platform_support);
    297		if (!error) {
    298			error = put_user(in_suspend, (int __user *)arg);
    299			data->ready = !freezer_test_done && !error;
    300			freezer_test_done = false;
    301		}
    302		break;
    303
    304	case SNAPSHOT_ATOMIC_RESTORE:
    305		snapshot_write_finalize(&data->handle);
    306		if (data->mode != O_WRONLY || !data->frozen ||
    307		    !snapshot_image_loaded(&data->handle)) {
    308			error = -EPERM;
    309			break;
    310		}
    311		error = hibernation_restore(data->platform_support);
    312		break;
    313
    314	case SNAPSHOT_FREE:
    315		swsusp_free();
    316		memset(&data->handle, 0, sizeof(struct snapshot_handle));
    317		data->ready = false;
    318		/*
    319		 * It is necessary to thaw kernel threads here, because
    320		 * SNAPSHOT_CREATE_IMAGE may be invoked directly after
    321		 * SNAPSHOT_FREE.  In that case, if kernel threads were not
    322		 * thawed, the preallocation of memory carried out by
    323		 * hibernation_snapshot() might run into problems (i.e. it
    324		 * might fail or even deadlock).
    325		 */
    326		thaw_kernel_threads();
    327		break;
    328
    329	case SNAPSHOT_PREF_IMAGE_SIZE:
    330		image_size = arg;
    331		break;
    332
    333	case SNAPSHOT_GET_IMAGE_SIZE:
    334		if (!data->ready) {
    335			error = -ENODATA;
    336			break;
    337		}
    338		size = snapshot_get_image_size();
    339		size <<= PAGE_SHIFT;
    340		error = put_user(size, (loff_t __user *)arg);
    341		break;
    342
    343	case SNAPSHOT_AVAIL_SWAP_SIZE:
    344		size = count_swap_pages(data->swap, 1);
    345		size <<= PAGE_SHIFT;
    346		error = put_user(size, (loff_t __user *)arg);
    347		break;
    348
    349	case SNAPSHOT_ALLOC_SWAP_PAGE:
    350		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
    351			error = -ENODEV;
    352			break;
    353		}
    354		offset = alloc_swapdev_block(data->swap);
    355		if (offset) {
    356			offset <<= PAGE_SHIFT;
    357			error = put_user(offset, (loff_t __user *)arg);
    358		} else {
    359			error = -ENOSPC;
    360		}
    361		break;
    362
    363	case SNAPSHOT_FREE_SWAP_PAGES:
    364		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
    365			error = -ENODEV;
    366			break;
    367		}
    368		free_all_swap_pages(data->swap);
    369		break;
    370
    371	case SNAPSHOT_S2RAM:
    372		if (!data->frozen) {
    373			error = -EPERM;
    374			break;
    375		}
    376		/*
    377		 * Tasks are frozen and the notifiers have been called with
    378		 * PM_HIBERNATION_PREPARE
    379		 */
    380		error = suspend_devices_and_enter(PM_SUSPEND_MEM);
    381		data->ready = false;
    382		break;
    383
    384	case SNAPSHOT_PLATFORM_SUPPORT:
    385		data->platform_support = !!arg;
    386		break;
    387
    388	case SNAPSHOT_POWER_OFF:
    389		if (data->platform_support)
    390			error = hibernation_platform_enter();
    391		break;
    392
    393	case SNAPSHOT_SET_SWAP_AREA:
    394		error = snapshot_set_swap_area(data, (void __user *)arg);
    395		break;
    396
    397	default:
    398		error = -ENOTTY;
    399
    400	}
    401
    402	unlock_device_hotplug();
    403	mutex_unlock(&system_transition_mutex);
    404
    405	return error;
    406}
    407
    408#ifdef CONFIG_COMPAT
    409static long
    410snapshot_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    411{
    412	BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
    413
    414	switch (cmd) {
    415	case SNAPSHOT_GET_IMAGE_SIZE:
    416	case SNAPSHOT_AVAIL_SWAP_SIZE:
    417	case SNAPSHOT_ALLOC_SWAP_PAGE:
    418	case SNAPSHOT_CREATE_IMAGE:
    419	case SNAPSHOT_SET_SWAP_AREA:
    420		return snapshot_ioctl(file, cmd,
    421				      (unsigned long) compat_ptr(arg));
    422	default:
    423		return snapshot_ioctl(file, cmd, arg);
    424	}
    425}
    426#endif /* CONFIG_COMPAT */
    427
    428static const struct file_operations snapshot_fops = {
    429	.open = snapshot_open,
    430	.release = snapshot_release,
    431	.read = snapshot_read,
    432	.write = snapshot_write,
    433	.llseek = no_llseek,
    434	.unlocked_ioctl = snapshot_ioctl,
    435#ifdef CONFIG_COMPAT
    436	.compat_ioctl = snapshot_compat_ioctl,
    437#endif
    438};
    439
    440static struct miscdevice snapshot_device = {
    441	.minor = SNAPSHOT_MINOR,
    442	.name = "snapshot",
    443	.fops = &snapshot_fops,
    444};
    445
    446static int __init snapshot_device_init(void)
    447{
    448	return misc_register(&snapshot_device);
    449};
    450
    451device_initcall(snapshot_device_init);