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

sthyi.c (12051B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * store hypervisor information instruction emulation functions.
      4 *
      5 * Copyright IBM Corp. 2016
      6 * Author(s): Janosch Frank <frankja@linux.vnet.ibm.com>
      7 */
      8#include <linux/errno.h>
      9#include <linux/pagemap.h>
     10#include <linux/vmalloc.h>
     11#include <linux/syscalls.h>
     12#include <linux/mutex.h>
     13#include <asm/asm-offsets.h>
     14#include <asm/sclp.h>
     15#include <asm/diag.h>
     16#include <asm/sysinfo.h>
     17#include <asm/ebcdic.h>
     18#include <asm/facility.h>
     19#include <asm/sthyi.h>
     20#include "entry.h"
     21
     22#define DED_WEIGHT 0xffff
     23/*
     24 * CP and IFL as EBCDIC strings, SP/0x40 determines the end of string
     25 * as they are justified with spaces.
     26 */
     27#define CP  0xc3d7404040404040UL
     28#define IFL 0xc9c6d34040404040UL
     29
     30enum hdr_flags {
     31	HDR_NOT_LPAR   = 0x10,
     32	HDR_STACK_INCM = 0x20,
     33	HDR_STSI_UNAV  = 0x40,
     34	HDR_PERF_UNAV  = 0x80,
     35};
     36
     37enum mac_validity {
     38	MAC_NAME_VLD = 0x20,
     39	MAC_ID_VLD   = 0x40,
     40	MAC_CNT_VLD  = 0x80,
     41};
     42
     43enum par_flag {
     44	PAR_MT_EN = 0x80,
     45};
     46
     47enum par_validity {
     48	PAR_GRP_VLD  = 0x08,
     49	PAR_ID_VLD   = 0x10,
     50	PAR_ABS_VLD  = 0x20,
     51	PAR_WGHT_VLD = 0x40,
     52	PAR_PCNT_VLD  = 0x80,
     53};
     54
     55struct hdr_sctn {
     56	u8 infhflg1;
     57	u8 infhflg2; /* reserved */
     58	u8 infhval1; /* reserved */
     59	u8 infhval2; /* reserved */
     60	u8 reserved[3];
     61	u8 infhygct;
     62	u16 infhtotl;
     63	u16 infhdln;
     64	u16 infmoff;
     65	u16 infmlen;
     66	u16 infpoff;
     67	u16 infplen;
     68	u16 infhoff1;
     69	u16 infhlen1;
     70	u16 infgoff1;
     71	u16 infglen1;
     72	u16 infhoff2;
     73	u16 infhlen2;
     74	u16 infgoff2;
     75	u16 infglen2;
     76	u16 infhoff3;
     77	u16 infhlen3;
     78	u16 infgoff3;
     79	u16 infglen3;
     80	u8 reserved2[4];
     81} __packed;
     82
     83struct mac_sctn {
     84	u8 infmflg1; /* reserved */
     85	u8 infmflg2; /* reserved */
     86	u8 infmval1;
     87	u8 infmval2; /* reserved */
     88	u16 infmscps;
     89	u16 infmdcps;
     90	u16 infmsifl;
     91	u16 infmdifl;
     92	char infmname[8];
     93	char infmtype[4];
     94	char infmmanu[16];
     95	char infmseq[16];
     96	char infmpman[4];
     97	u8 reserved[4];
     98} __packed;
     99
    100struct par_sctn {
    101	u8 infpflg1;
    102	u8 infpflg2; /* reserved */
    103	u8 infpval1;
    104	u8 infpval2; /* reserved */
    105	u16 infppnum;
    106	u16 infpscps;
    107	u16 infpdcps;
    108	u16 infpsifl;
    109	u16 infpdifl;
    110	u16 reserved;
    111	char infppnam[8];
    112	u32 infpwbcp;
    113	u32 infpabcp;
    114	u32 infpwbif;
    115	u32 infpabif;
    116	char infplgnm[8];
    117	u32 infplgcp;
    118	u32 infplgif;
    119} __packed;
    120
    121struct sthyi_sctns {
    122	struct hdr_sctn hdr;
    123	struct mac_sctn mac;
    124	struct par_sctn par;
    125} __packed;
    126
    127struct cpu_inf {
    128	u64 lpar_cap;
    129	u64 lpar_grp_cap;
    130	u64 lpar_weight;
    131	u64 all_weight;
    132	int cpu_num_ded;
    133	int cpu_num_shd;
    134};
    135
    136struct lpar_cpu_inf {
    137	struct cpu_inf cp;
    138	struct cpu_inf ifl;
    139};
    140
    141/*
    142 * STHYI requires extensive locking in the higher hypervisors
    143 * and is very computational/memory expensive. Therefore we
    144 * cache the retrieved data whose valid period is 1s.
    145 */
    146#define CACHE_VALID_JIFFIES	HZ
    147
    148struct sthyi_info {
    149	void *info;
    150	unsigned long end;
    151};
    152
    153static DEFINE_MUTEX(sthyi_mutex);
    154static struct sthyi_info sthyi_cache;
    155
    156static inline u64 cpu_id(u8 ctidx, void *diag224_buf)
    157{
    158	return *((u64 *)(diag224_buf + (ctidx + 1) * DIAG204_CPU_NAME_LEN));
    159}
    160
    161/*
    162 * Scales the cpu capping from the lpar range to the one expected in
    163 * sthyi data.
    164 *
    165 * diag204 reports a cap in hundredths of processor units.
    166 * z/VM's range for one core is 0 - 0x10000.
    167 */
    168static u32 scale_cap(u32 in)
    169{
    170	return (0x10000 * in) / 100;
    171}
    172
    173static void fill_hdr(struct sthyi_sctns *sctns)
    174{
    175	sctns->hdr.infhdln = sizeof(sctns->hdr);
    176	sctns->hdr.infmoff = sizeof(sctns->hdr);
    177	sctns->hdr.infmlen = sizeof(sctns->mac);
    178	sctns->hdr.infplen = sizeof(sctns->par);
    179	sctns->hdr.infpoff = sctns->hdr.infhdln + sctns->hdr.infmlen;
    180	sctns->hdr.infhtotl = sctns->hdr.infpoff + sctns->hdr.infplen;
    181}
    182
    183static void fill_stsi_mac(struct sthyi_sctns *sctns,
    184			  struct sysinfo_1_1_1 *sysinfo)
    185{
    186	sclp_ocf_cpc_name_copy(sctns->mac.infmname);
    187	if (*(u64 *)sctns->mac.infmname != 0)
    188		sctns->mac.infmval1 |= MAC_NAME_VLD;
    189
    190	if (stsi(sysinfo, 1, 1, 1))
    191		return;
    192
    193	memcpy(sctns->mac.infmtype, sysinfo->type, sizeof(sctns->mac.infmtype));
    194	memcpy(sctns->mac.infmmanu, sysinfo->manufacturer, sizeof(sctns->mac.infmmanu));
    195	memcpy(sctns->mac.infmpman, sysinfo->plant, sizeof(sctns->mac.infmpman));
    196	memcpy(sctns->mac.infmseq, sysinfo->sequence, sizeof(sctns->mac.infmseq));
    197
    198	sctns->mac.infmval1 |= MAC_ID_VLD;
    199}
    200
    201static void fill_stsi_par(struct sthyi_sctns *sctns,
    202			  struct sysinfo_2_2_2 *sysinfo)
    203{
    204	if (stsi(sysinfo, 2, 2, 2))
    205		return;
    206
    207	sctns->par.infppnum = sysinfo->lpar_number;
    208	memcpy(sctns->par.infppnam, sysinfo->name, sizeof(sctns->par.infppnam));
    209
    210	sctns->par.infpval1 |= PAR_ID_VLD;
    211}
    212
    213static void fill_stsi(struct sthyi_sctns *sctns)
    214{
    215	void *sysinfo;
    216
    217	/* Errors are handled through the validity bits in the response. */
    218	sysinfo = (void *)__get_free_page(GFP_KERNEL);
    219	if (!sysinfo)
    220		return;
    221
    222	fill_stsi_mac(sctns, sysinfo);
    223	fill_stsi_par(sctns, sysinfo);
    224
    225	free_pages((unsigned long)sysinfo, 0);
    226}
    227
    228static void fill_diag_mac(struct sthyi_sctns *sctns,
    229			  struct diag204_x_phys_block *block,
    230			  void *diag224_buf)
    231{
    232	int i;
    233
    234	for (i = 0; i < block->hdr.cpus; i++) {
    235		switch (cpu_id(block->cpus[i].ctidx, diag224_buf)) {
    236		case CP:
    237			if (block->cpus[i].weight == DED_WEIGHT)
    238				sctns->mac.infmdcps++;
    239			else
    240				sctns->mac.infmscps++;
    241			break;
    242		case IFL:
    243			if (block->cpus[i].weight == DED_WEIGHT)
    244				sctns->mac.infmdifl++;
    245			else
    246				sctns->mac.infmsifl++;
    247			break;
    248		}
    249	}
    250	sctns->mac.infmval1 |= MAC_CNT_VLD;
    251}
    252
    253/* Returns a pointer to the the next partition block. */
    254static struct diag204_x_part_block *lpar_cpu_inf(struct lpar_cpu_inf *part_inf,
    255						 bool this_lpar,
    256						 void *diag224_buf,
    257						 struct diag204_x_part_block *block)
    258{
    259	int i, capped = 0, weight_cp = 0, weight_ifl = 0;
    260	struct cpu_inf *cpu_inf;
    261
    262	for (i = 0; i < block->hdr.rcpus; i++) {
    263		if (!(block->cpus[i].cflag & DIAG204_CPU_ONLINE))
    264			continue;
    265
    266		switch (cpu_id(block->cpus[i].ctidx, diag224_buf)) {
    267		case CP:
    268			cpu_inf = &part_inf->cp;
    269			if (block->cpus[i].cur_weight < DED_WEIGHT)
    270				weight_cp |= block->cpus[i].cur_weight;
    271			break;
    272		case IFL:
    273			cpu_inf = &part_inf->ifl;
    274			if (block->cpus[i].cur_weight < DED_WEIGHT)
    275				weight_ifl |= block->cpus[i].cur_weight;
    276			break;
    277		default:
    278			continue;
    279		}
    280
    281		if (!this_lpar)
    282			continue;
    283
    284		capped |= block->cpus[i].cflag & DIAG204_CPU_CAPPED;
    285		cpu_inf->lpar_cap |= block->cpus[i].cpu_type_cap;
    286		cpu_inf->lpar_grp_cap |= block->cpus[i].group_cpu_type_cap;
    287
    288		if (block->cpus[i].weight == DED_WEIGHT)
    289			cpu_inf->cpu_num_ded += 1;
    290		else
    291			cpu_inf->cpu_num_shd += 1;
    292	}
    293
    294	if (this_lpar && capped) {
    295		part_inf->cp.lpar_weight = weight_cp;
    296		part_inf->ifl.lpar_weight = weight_ifl;
    297	}
    298	part_inf->cp.all_weight += weight_cp;
    299	part_inf->ifl.all_weight += weight_ifl;
    300	return (struct diag204_x_part_block *)&block->cpus[i];
    301}
    302
    303static void fill_diag(struct sthyi_sctns *sctns)
    304{
    305	int i, r, pages;
    306	bool this_lpar;
    307	void *diag204_buf;
    308	void *diag224_buf = NULL;
    309	struct diag204_x_info_blk_hdr *ti_hdr;
    310	struct diag204_x_part_block *part_block;
    311	struct diag204_x_phys_block *phys_block;
    312	struct lpar_cpu_inf lpar_inf = {};
    313
    314	/* Errors are handled through the validity bits in the response. */
    315	pages = diag204((unsigned long)DIAG204_SUBC_RSI |
    316			(unsigned long)DIAG204_INFO_EXT, 0, NULL);
    317	if (pages <= 0)
    318		return;
    319
    320	diag204_buf = vmalloc(array_size(pages, PAGE_SIZE));
    321	if (!diag204_buf)
    322		return;
    323
    324	r = diag204((unsigned long)DIAG204_SUBC_STIB7 |
    325		    (unsigned long)DIAG204_INFO_EXT, pages, diag204_buf);
    326	if (r < 0)
    327		goto out;
    328
    329	diag224_buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
    330	if (!diag224_buf || diag224(diag224_buf))
    331		goto out;
    332
    333	ti_hdr = diag204_buf;
    334	part_block = diag204_buf + sizeof(*ti_hdr);
    335
    336	for (i = 0; i < ti_hdr->npar; i++) {
    337		/*
    338		 * For the calling lpar we also need to get the cpu
    339		 * caps and weights. The time information block header
    340		 * specifies the offset to the partition block of the
    341		 * caller lpar, so we know when we process its data.
    342		 */
    343		this_lpar = (void *)part_block - diag204_buf == ti_hdr->this_part;
    344		part_block = lpar_cpu_inf(&lpar_inf, this_lpar, diag224_buf,
    345					  part_block);
    346	}
    347
    348	phys_block = (struct diag204_x_phys_block *)part_block;
    349	part_block = diag204_buf + ti_hdr->this_part;
    350	if (part_block->hdr.mtid)
    351		sctns->par.infpflg1 = PAR_MT_EN;
    352
    353	sctns->par.infpval1 |= PAR_GRP_VLD;
    354	sctns->par.infplgcp = scale_cap(lpar_inf.cp.lpar_grp_cap);
    355	sctns->par.infplgif = scale_cap(lpar_inf.ifl.lpar_grp_cap);
    356	memcpy(sctns->par.infplgnm, part_block->hdr.hardware_group_name,
    357	       sizeof(sctns->par.infplgnm));
    358
    359	sctns->par.infpscps = lpar_inf.cp.cpu_num_shd;
    360	sctns->par.infpdcps = lpar_inf.cp.cpu_num_ded;
    361	sctns->par.infpsifl = lpar_inf.ifl.cpu_num_shd;
    362	sctns->par.infpdifl = lpar_inf.ifl.cpu_num_ded;
    363	sctns->par.infpval1 |= PAR_PCNT_VLD;
    364
    365	sctns->par.infpabcp = scale_cap(lpar_inf.cp.lpar_cap);
    366	sctns->par.infpabif = scale_cap(lpar_inf.ifl.lpar_cap);
    367	sctns->par.infpval1 |= PAR_ABS_VLD;
    368
    369	/*
    370	 * Everything below needs global performance data to be
    371	 * meaningful.
    372	 */
    373	if (!(ti_hdr->flags & DIAG204_LPAR_PHYS_FLG)) {
    374		sctns->hdr.infhflg1 |= HDR_PERF_UNAV;
    375		goto out;
    376	}
    377
    378	fill_diag_mac(sctns, phys_block, diag224_buf);
    379
    380	if (lpar_inf.cp.lpar_weight) {
    381		sctns->par.infpwbcp = sctns->mac.infmscps * 0x10000 *
    382			lpar_inf.cp.lpar_weight / lpar_inf.cp.all_weight;
    383	}
    384
    385	if (lpar_inf.ifl.lpar_weight) {
    386		sctns->par.infpwbif = sctns->mac.infmsifl * 0x10000 *
    387			lpar_inf.ifl.lpar_weight / lpar_inf.ifl.all_weight;
    388	}
    389	sctns->par.infpval1 |= PAR_WGHT_VLD;
    390
    391out:
    392	free_page((unsigned long)diag224_buf);
    393	vfree(diag204_buf);
    394}
    395
    396static int sthyi(u64 vaddr, u64 *rc)
    397{
    398	union register_pair r1 = { .even = 0, }; /* subcode */
    399	union register_pair r2 = { .even = vaddr, };
    400	int cc;
    401
    402	asm volatile(
    403		".insn   rre,0xB2560000,%[r1],%[r2]\n"
    404		"ipm     %[cc]\n"
    405		"srl     %[cc],28\n"
    406		: [cc] "=&d" (cc), [r2] "+&d" (r2.pair)
    407		: [r1] "d" (r1.pair)
    408		: "memory", "cc");
    409	*rc = r2.odd;
    410	return cc;
    411}
    412
    413static int fill_dst(void *dst, u64 *rc)
    414{
    415	struct sthyi_sctns *sctns = (struct sthyi_sctns *)dst;
    416
    417	/*
    418	 * If the facility is on, we don't want to emulate the instruction.
    419	 * We ask the hypervisor to provide the data.
    420	 */
    421	if (test_facility(74))
    422		return sthyi((u64)dst, rc);
    423
    424	fill_hdr(sctns);
    425	fill_stsi(sctns);
    426	fill_diag(sctns);
    427	*rc = 0;
    428	return 0;
    429}
    430
    431static int sthyi_init_cache(void)
    432{
    433	if (sthyi_cache.info)
    434		return 0;
    435	sthyi_cache.info = (void *)get_zeroed_page(GFP_KERNEL);
    436	if (!sthyi_cache.info)
    437		return -ENOMEM;
    438	sthyi_cache.end = jiffies - 1; /* expired */
    439	return 0;
    440}
    441
    442static int sthyi_update_cache(u64 *rc)
    443{
    444	int r;
    445
    446	memset(sthyi_cache.info, 0, PAGE_SIZE);
    447	r = fill_dst(sthyi_cache.info, rc);
    448	if (r)
    449		return r;
    450	sthyi_cache.end = jiffies + CACHE_VALID_JIFFIES;
    451	return r;
    452}
    453
    454/*
    455 * sthyi_fill - Fill page with data returned by the STHYI instruction
    456 *
    457 * @dst: Pointer to zeroed page
    458 * @rc:  Pointer for storing the return code of the instruction
    459 *
    460 * Fills the destination with system information returned by the STHYI
    461 * instruction. The data is generated by emulation or execution of STHYI,
    462 * if available. The return value is the condition code that would be
    463 * returned, the rc parameter is the return code which is passed in
    464 * register R2 + 1.
    465 */
    466int sthyi_fill(void *dst, u64 *rc)
    467{
    468	int r;
    469
    470	mutex_lock(&sthyi_mutex);
    471	r = sthyi_init_cache();
    472	if (r)
    473		goto out;
    474
    475	if (time_is_before_jiffies(sthyi_cache.end)) {
    476		/* cache expired */
    477		r = sthyi_update_cache(rc);
    478		if (r)
    479			goto out;
    480	}
    481	*rc = 0;
    482	memcpy(dst, sthyi_cache.info, PAGE_SIZE);
    483out:
    484	mutex_unlock(&sthyi_mutex);
    485	return r;
    486}
    487EXPORT_SYMBOL_GPL(sthyi_fill);
    488
    489SYSCALL_DEFINE4(s390_sthyi, unsigned long, function_code, void __user *, buffer,
    490		u64 __user *, return_code, unsigned long, flags)
    491{
    492	u64 sthyi_rc;
    493	void *info;
    494	int r;
    495
    496	if (flags)
    497		return -EINVAL;
    498	if (function_code != STHYI_FC_CP_IFL_CAP)
    499		return -EOPNOTSUPP;
    500	info = (void *)get_zeroed_page(GFP_KERNEL);
    501	if (!info)
    502		return -ENOMEM;
    503	r = sthyi_fill(info, &sthyi_rc);
    504	if (r < 0)
    505		goto out;
    506	if (return_code && put_user(sthyi_rc, return_code)) {
    507		r = -EFAULT;
    508		goto out;
    509	}
    510	if (copy_to_user(buffer, info, PAGE_SIZE))
    511		r = -EFAULT;
    512out:
    513	free_page((unsigned long)info);
    514	return r;
    515}