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

guarded_storage.c (2502B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright IBM Corp. 2016
      4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
      5 */
      6
      7#include <linux/kernel.h>
      8#include <linux/syscalls.h>
      9#include <linux/signal.h>
     10#include <linux/mm.h>
     11#include <linux/slab.h>
     12#include <asm/guarded_storage.h>
     13#include "entry.h"
     14
     15void guarded_storage_release(struct task_struct *tsk)
     16{
     17	kfree(tsk->thread.gs_cb);
     18	kfree(tsk->thread.gs_bc_cb);
     19}
     20
     21static int gs_enable(void)
     22{
     23	struct gs_cb *gs_cb;
     24
     25	if (!current->thread.gs_cb) {
     26		gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
     27		if (!gs_cb)
     28			return -ENOMEM;
     29		gs_cb->gsd = 25;
     30		preempt_disable();
     31		__ctl_set_bit(2, 4);
     32		load_gs_cb(gs_cb);
     33		current->thread.gs_cb = gs_cb;
     34		preempt_enable();
     35	}
     36	return 0;
     37}
     38
     39static int gs_disable(void)
     40{
     41	if (current->thread.gs_cb) {
     42		preempt_disable();
     43		kfree(current->thread.gs_cb);
     44		current->thread.gs_cb = NULL;
     45		__ctl_clear_bit(2, 4);
     46		preempt_enable();
     47	}
     48	return 0;
     49}
     50
     51static int gs_set_bc_cb(struct gs_cb __user *u_gs_cb)
     52{
     53	struct gs_cb *gs_cb;
     54
     55	gs_cb = current->thread.gs_bc_cb;
     56	if (!gs_cb) {
     57		gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
     58		if (!gs_cb)
     59			return -ENOMEM;
     60		current->thread.gs_bc_cb = gs_cb;
     61	}
     62	if (copy_from_user(gs_cb, u_gs_cb, sizeof(*gs_cb)))
     63		return -EFAULT;
     64	return 0;
     65}
     66
     67static int gs_clear_bc_cb(void)
     68{
     69	struct gs_cb *gs_cb;
     70
     71	gs_cb = current->thread.gs_bc_cb;
     72	current->thread.gs_bc_cb = NULL;
     73	kfree(gs_cb);
     74	return 0;
     75}
     76
     77void gs_load_bc_cb(struct pt_regs *regs)
     78{
     79	struct gs_cb *gs_cb;
     80
     81	preempt_disable();
     82	clear_thread_flag(TIF_GUARDED_STORAGE);
     83	gs_cb = current->thread.gs_bc_cb;
     84	if (gs_cb) {
     85		kfree(current->thread.gs_cb);
     86		current->thread.gs_bc_cb = NULL;
     87		__ctl_set_bit(2, 4);
     88		load_gs_cb(gs_cb);
     89		current->thread.gs_cb = gs_cb;
     90	}
     91	preempt_enable();
     92}
     93
     94static int gs_broadcast(void)
     95{
     96	struct task_struct *sibling;
     97
     98	read_lock(&tasklist_lock);
     99	for_each_thread(current, sibling) {
    100		if (!sibling->thread.gs_bc_cb)
    101			continue;
    102		if (test_and_set_tsk_thread_flag(sibling, TIF_GUARDED_STORAGE))
    103			kick_process(sibling);
    104	}
    105	read_unlock(&tasklist_lock);
    106	return 0;
    107}
    108
    109SYSCALL_DEFINE2(s390_guarded_storage, int, command,
    110		struct gs_cb __user *, gs_cb)
    111{
    112	if (!MACHINE_HAS_GS)
    113		return -EOPNOTSUPP;
    114	switch (command) {
    115	case GS_ENABLE:
    116		return gs_enable();
    117	case GS_DISABLE:
    118		return gs_disable();
    119	case GS_SET_BC_CB:
    120		return gs_set_bc_cb(gs_cb);
    121	case GS_CLEAR_BC_CB:
    122		return gs_clear_bc_cb();
    123	case GS_BROADCAST:
    124		return gs_broadcast();
    125	default:
    126		return -EINVAL;
    127	}
    128}