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

hypfs_diag0c.c (2782B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Hypervisor filesystem for Linux on s390
      4 *
      5 * Diag 0C implementation
      6 *
      7 * Copyright IBM Corp. 2014
      8 */
      9
     10#include <linux/slab.h>
     11#include <linux/cpu.h>
     12#include <asm/diag.h>
     13#include <asm/hypfs.h>
     14#include "hypfs.h"
     15
     16#define DBFS_D0C_HDR_VERSION 0
     17
     18/*
     19 * Get hypfs_diag0c_entry from CPU vector and store diag0c data
     20 */
     21static void diag0c_fn(void *data)
     22{
     23	diag_stat_inc(DIAG_STAT_X00C);
     24	diag_amode31_ops.diag0c(((void **)data)[smp_processor_id()]);
     25}
     26
     27/*
     28 * Allocate buffer and store diag 0c data
     29 */
     30static void *diag0c_store(unsigned int *count)
     31{
     32	struct hypfs_diag0c_data *diag0c_data;
     33	unsigned int cpu_count, cpu, i;
     34	void **cpu_vec;
     35
     36	cpus_read_lock();
     37	cpu_count = num_online_cpus();
     38	cpu_vec = kmalloc_array(num_possible_cpus(), sizeof(*cpu_vec),
     39				GFP_KERNEL);
     40	if (!cpu_vec)
     41		goto fail_unlock_cpus;
     42	/* Note: Diag 0c needs 8 byte alignment and real storage */
     43	diag0c_data = kzalloc(struct_size(diag0c_data, entry, cpu_count),
     44			      GFP_KERNEL | GFP_DMA);
     45	if (!diag0c_data)
     46		goto fail_kfree_cpu_vec;
     47	i = 0;
     48	/* Fill CPU vector for each online CPU */
     49	for_each_online_cpu(cpu) {
     50		diag0c_data->entry[i].cpu = cpu;
     51		cpu_vec[cpu] = &diag0c_data->entry[i++];
     52	}
     53	/* Collect data all CPUs */
     54	on_each_cpu(diag0c_fn, cpu_vec, 1);
     55	*count = cpu_count;
     56	kfree(cpu_vec);
     57	cpus_read_unlock();
     58	return diag0c_data;
     59
     60fail_kfree_cpu_vec:
     61	kfree(cpu_vec);
     62fail_unlock_cpus:
     63	cpus_read_unlock();
     64	return ERR_PTR(-ENOMEM);
     65}
     66
     67/*
     68 * Hypfs DBFS callback: Free diag 0c data
     69 */
     70static void dbfs_diag0c_free(const void *data)
     71{
     72	kfree(data);
     73}
     74
     75/*
     76 * Hypfs DBFS callback: Create diag 0c data
     77 */
     78static int dbfs_diag0c_create(void **data, void **data_free_ptr, size_t *size)
     79{
     80	struct hypfs_diag0c_data *diag0c_data;
     81	unsigned int count;
     82
     83	diag0c_data = diag0c_store(&count);
     84	if (IS_ERR(diag0c_data))
     85		return PTR_ERR(diag0c_data);
     86	memset(&diag0c_data->hdr, 0, sizeof(diag0c_data->hdr));
     87	store_tod_clock_ext((union tod_clock *)diag0c_data->hdr.tod_ext);
     88	diag0c_data->hdr.len = count * sizeof(struct hypfs_diag0c_entry);
     89	diag0c_data->hdr.version = DBFS_D0C_HDR_VERSION;
     90	diag0c_data->hdr.count = count;
     91	*data = diag0c_data;
     92	*data_free_ptr = diag0c_data;
     93	*size = diag0c_data->hdr.len + sizeof(struct hypfs_diag0c_hdr);
     94	return 0;
     95}
     96
     97/*
     98 * Hypfs DBFS file structure
     99 */
    100static struct hypfs_dbfs_file dbfs_file_0c = {
    101	.name		= "diag_0c",
    102	.data_create	= dbfs_diag0c_create,
    103	.data_free	= dbfs_diag0c_free,
    104};
    105
    106/*
    107 * Initialize diag 0c interface for z/VM
    108 */
    109int __init hypfs_diag0c_init(void)
    110{
    111	if (!MACHINE_IS_VM)
    112		return 0;
    113	hypfs_dbfs_create_file(&dbfs_file_0c);
    114	return 0;
    115}
    116
    117/*
    118 * Shutdown diag 0c interface for z/VM
    119 */
    120void hypfs_diag0c_exit(void)
    121{
    122	if (!MACHINE_IS_VM)
    123		return;
    124	hypfs_dbfs_remove_file(&dbfs_file_0c);
    125}