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_vm.c (7000B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *    Hypervisor filesystem for Linux on s390. z/VM implementation.
      4 *
      5 *    Copyright IBM Corp. 2006
      6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
      7 */
      8
      9#include <linux/types.h>
     10#include <linux/errno.h>
     11#include <linux/string.h>
     12#include <linux/vmalloc.h>
     13#include <asm/extable.h>
     14#include <asm/diag.h>
     15#include <asm/ebcdic.h>
     16#include <asm/timex.h>
     17#include "hypfs.h"
     18
     19#define NAME_LEN 8
     20#define DBFS_D2FC_HDR_VERSION 0
     21
     22static char local_guest[] = "        ";
     23static char all_guests[] = "*       ";
     24static char *all_groups = all_guests;
     25static char *guest_query;
     26
     27struct diag2fc_data {
     28	__u32 version;
     29	__u32 flags;
     30	__u64 used_cpu;
     31	__u64 el_time;
     32	__u64 mem_min_kb;
     33	__u64 mem_max_kb;
     34	__u64 mem_share_kb;
     35	__u64 mem_used_kb;
     36	__u32 pcpus;
     37	__u32 lcpus;
     38	__u32 vcpus;
     39	__u32 ocpus;
     40	__u32 cpu_max;
     41	__u32 cpu_shares;
     42	__u32 cpu_use_samp;
     43	__u32 cpu_delay_samp;
     44	__u32 page_wait_samp;
     45	__u32 idle_samp;
     46	__u32 other_samp;
     47	__u32 total_samp;
     48	char  guest_name[NAME_LEN];
     49};
     50
     51struct diag2fc_parm_list {
     52	char userid[NAME_LEN];
     53	char aci_grp[NAME_LEN];
     54	__u64 addr;
     55	__u32 size;
     56	__u32 fmt;
     57};
     58
     59static int diag2fc(int size, char* query, void *addr)
     60{
     61	unsigned long residual_cnt;
     62	unsigned long rc;
     63	struct diag2fc_parm_list parm_list;
     64
     65	memcpy(parm_list.userid, query, NAME_LEN);
     66	ASCEBC(parm_list.userid, NAME_LEN);
     67	memcpy(parm_list.aci_grp, all_groups, NAME_LEN);
     68	ASCEBC(parm_list.aci_grp, NAME_LEN);
     69	parm_list.addr = (unsigned long)addr;
     70	parm_list.size = size;
     71	parm_list.fmt = 0x02;
     72	rc = -1;
     73
     74	diag_stat_inc(DIAG_STAT_X2FC);
     75	asm volatile(
     76		"	diag    %0,%1,0x2fc\n"
     77		"0:	nopr	%%r7\n"
     78		EX_TABLE(0b,0b)
     79		: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
     80
     81	if ((rc != 0 ) && (rc != -2))
     82		return rc;
     83	else
     84		return -residual_cnt;
     85}
     86
     87/*
     88 * Allocate buffer for "query" and store diag 2fc at "offset"
     89 */
     90static void *diag2fc_store(char *query, unsigned int *count, int offset)
     91{
     92	void *data;
     93	int size;
     94
     95	do {
     96		size = diag2fc(0, query, NULL);
     97		if (size < 0)
     98			return ERR_PTR(-EACCES);
     99		data = vmalloc(size + offset);
    100		if (!data)
    101			return ERR_PTR(-ENOMEM);
    102		if (diag2fc(size, query, data + offset) == 0)
    103			break;
    104		vfree(data);
    105	} while (1);
    106	*count = (size / sizeof(struct diag2fc_data));
    107
    108	return data;
    109}
    110
    111static void diag2fc_free(const void *data)
    112{
    113	vfree(data);
    114}
    115
    116#define ATTRIBUTE(dir, name, member) \
    117do { \
    118	void *rc; \
    119	rc = hypfs_create_u64(dir, name, member); \
    120	if (IS_ERR(rc)) \
    121		return PTR_ERR(rc); \
    122} while(0)
    123
    124static int hypfs_vm_create_guest(struct dentry *systems_dir,
    125				 struct diag2fc_data *data)
    126{
    127	char guest_name[NAME_LEN + 1] = {};
    128	struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
    129	int dedicated_flag, capped_value;
    130
    131	capped_value = (data->flags & 0x00000006) >> 1;
    132	dedicated_flag = (data->flags & 0x00000008) >> 3;
    133
    134	/* guest dir */
    135	memcpy(guest_name, data->guest_name, NAME_LEN);
    136	EBCASC(guest_name, NAME_LEN);
    137	strim(guest_name);
    138	guest_dir = hypfs_mkdir(systems_dir, guest_name);
    139	if (IS_ERR(guest_dir))
    140		return PTR_ERR(guest_dir);
    141	ATTRIBUTE(guest_dir, "onlinetime_us", data->el_time);
    142
    143	/* logical cpu information */
    144	cpus_dir = hypfs_mkdir(guest_dir, "cpus");
    145	if (IS_ERR(cpus_dir))
    146		return PTR_ERR(cpus_dir);
    147	ATTRIBUTE(cpus_dir, "cputime_us", data->used_cpu);
    148	ATTRIBUTE(cpus_dir, "capped", capped_value);
    149	ATTRIBUTE(cpus_dir, "dedicated", dedicated_flag);
    150	ATTRIBUTE(cpus_dir, "count", data->vcpus);
    151	/*
    152	 * Note: The "weight_min" attribute got the wrong name.
    153	 * The value represents the number of non-stopped (operating)
    154	 * CPUS.
    155	 */
    156	ATTRIBUTE(cpus_dir, "weight_min", data->ocpus);
    157	ATTRIBUTE(cpus_dir, "weight_max", data->cpu_max);
    158	ATTRIBUTE(cpus_dir, "weight_cur", data->cpu_shares);
    159
    160	/* memory information */
    161	mem_dir = hypfs_mkdir(guest_dir, "mem");
    162	if (IS_ERR(mem_dir))
    163		return PTR_ERR(mem_dir);
    164	ATTRIBUTE(mem_dir, "min_KiB", data->mem_min_kb);
    165	ATTRIBUTE(mem_dir, "max_KiB", data->mem_max_kb);
    166	ATTRIBUTE(mem_dir, "used_KiB", data->mem_used_kb);
    167	ATTRIBUTE(mem_dir, "share_KiB", data->mem_share_kb);
    168
    169	/* samples */
    170	samples_dir = hypfs_mkdir(guest_dir, "samples");
    171	if (IS_ERR(samples_dir))
    172		return PTR_ERR(samples_dir);
    173	ATTRIBUTE(samples_dir, "cpu_using", data->cpu_use_samp);
    174	ATTRIBUTE(samples_dir, "cpu_delay", data->cpu_delay_samp);
    175	ATTRIBUTE(samples_dir, "mem_delay", data->page_wait_samp);
    176	ATTRIBUTE(samples_dir, "idle", data->idle_samp);
    177	ATTRIBUTE(samples_dir, "other", data->other_samp);
    178	ATTRIBUTE(samples_dir, "total", data->total_samp);
    179	return 0;
    180}
    181
    182int hypfs_vm_create_files(struct dentry *root)
    183{
    184	struct dentry *dir, *file;
    185	struct diag2fc_data *data;
    186	unsigned int count = 0;
    187	int rc, i;
    188
    189	data = diag2fc_store(guest_query, &count, 0);
    190	if (IS_ERR(data))
    191		return PTR_ERR(data);
    192
    193	/* Hypervisor Info */
    194	dir = hypfs_mkdir(root, "hyp");
    195	if (IS_ERR(dir)) {
    196		rc = PTR_ERR(dir);
    197		goto failed;
    198	}
    199	file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
    200	if (IS_ERR(file)) {
    201		rc = PTR_ERR(file);
    202		goto failed;
    203	}
    204
    205	/* physical cpus */
    206	dir = hypfs_mkdir(root, "cpus");
    207	if (IS_ERR(dir)) {
    208		rc = PTR_ERR(dir);
    209		goto failed;
    210	}
    211	file = hypfs_create_u64(dir, "count", data->lcpus);
    212	if (IS_ERR(file)) {
    213		rc = PTR_ERR(file);
    214		goto failed;
    215	}
    216
    217	/* guests */
    218	dir = hypfs_mkdir(root, "systems");
    219	if (IS_ERR(dir)) {
    220		rc = PTR_ERR(dir);
    221		goto failed;
    222	}
    223
    224	for (i = 0; i < count; i++) {
    225		rc = hypfs_vm_create_guest(dir, &(data[i]));
    226		if (rc)
    227			goto failed;
    228	}
    229	diag2fc_free(data);
    230	return 0;
    231
    232failed:
    233	diag2fc_free(data);
    234	return rc;
    235}
    236
    237struct dbfs_d2fc_hdr {
    238	u64	len;		/* Length of d2fc buffer without header */
    239	u16	version;	/* Version of header */
    240	union tod_clock tod_ext; /* TOD clock for d2fc */
    241	u64	count;		/* Number of VM guests in d2fc buffer */
    242	char	reserved[30];
    243} __attribute__ ((packed));
    244
    245struct dbfs_d2fc {
    246	struct dbfs_d2fc_hdr	hdr;	/* 64 byte header */
    247	char			buf[];	/* d2fc buffer */
    248} __attribute__ ((packed));
    249
    250static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
    251{
    252	struct dbfs_d2fc *d2fc;
    253	unsigned int count;
    254
    255	d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
    256	if (IS_ERR(d2fc))
    257		return PTR_ERR(d2fc);
    258	store_tod_clock_ext(&d2fc->hdr.tod_ext);
    259	d2fc->hdr.len = count * sizeof(struct diag2fc_data);
    260	d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
    261	d2fc->hdr.count = count;
    262	memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
    263	*data = d2fc;
    264	*data_free_ptr = d2fc;
    265	*size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
    266	return 0;
    267}
    268
    269static struct hypfs_dbfs_file dbfs_file_2fc = {
    270	.name		= "diag_2fc",
    271	.data_create	= dbfs_diag2fc_create,
    272	.data_free	= diag2fc_free,
    273};
    274
    275int hypfs_vm_init(void)
    276{
    277	if (!MACHINE_IS_VM)
    278		return 0;
    279	if (diag2fc(0, all_guests, NULL) > 0)
    280		guest_query = all_guests;
    281	else if (diag2fc(0, local_guest, NULL) > 0)
    282		guest_query = local_guest;
    283	else
    284		return -EACCES;
    285	hypfs_dbfs_create_file(&dbfs_file_2fc);
    286	return 0;
    287}
    288
    289void hypfs_vm_exit(void)
    290{
    291	if (!MACHINE_IS_VM)
    292		return;
    293	hypfs_dbfs_remove_file(&dbfs_file_2fc);
    294}