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

plpar_wrappers.h (10169B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2#ifndef _ASM_POWERPC_PLPAR_WRAPPERS_H
      3#define _ASM_POWERPC_PLPAR_WRAPPERS_H
      4
      5#ifdef CONFIG_PPC_PSERIES
      6
      7#include <linux/string.h>
      8#include <linux/irqflags.h>
      9
     10#include <asm/hvcall.h>
     11#include <asm/paca.h>
     12#include <asm/page.h>
     13
     14static inline long poll_pending(void)
     15{
     16	return plpar_hcall_norets(H_POLL_PENDING);
     17}
     18
     19static inline u8 get_cede_latency_hint(void)
     20{
     21	return get_lppaca()->cede_latency_hint;
     22}
     23
     24static inline void set_cede_latency_hint(u8 latency_hint)
     25{
     26	get_lppaca()->cede_latency_hint = latency_hint;
     27}
     28
     29static inline long cede_processor(void)
     30{
     31	/*
     32	 * We cannot call tracepoints inside RCU idle regions which
     33	 * means we must not trace H_CEDE.
     34	 */
     35	return plpar_hcall_norets_notrace(H_CEDE);
     36}
     37
     38static inline long extended_cede_processor(unsigned long latency_hint)
     39{
     40	long rc;
     41	u8 old_latency_hint = get_cede_latency_hint();
     42
     43	set_cede_latency_hint(latency_hint);
     44
     45	rc = cede_processor();
     46#ifdef CONFIG_PPC_IRQ_SOFT_MASK_DEBUG
     47	/* Ensure that H_CEDE returns with IRQs on */
     48	if (WARN_ON(!(mfmsr() & MSR_EE)))
     49		__hard_irq_enable();
     50#endif
     51
     52	set_cede_latency_hint(old_latency_hint);
     53
     54	return rc;
     55}
     56
     57static inline long vpa_call(unsigned long flags, unsigned long cpu,
     58		unsigned long vpa)
     59{
     60	flags = flags << H_VPA_FUNC_SHIFT;
     61
     62	return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
     63}
     64
     65static inline long unregister_vpa(unsigned long cpu)
     66{
     67	return vpa_call(H_VPA_DEREG_VPA, cpu, 0);
     68}
     69
     70static inline long register_vpa(unsigned long cpu, unsigned long vpa)
     71{
     72	return vpa_call(H_VPA_REG_VPA, cpu, vpa);
     73}
     74
     75static inline long unregister_slb_shadow(unsigned long cpu)
     76{
     77	return vpa_call(H_VPA_DEREG_SLB, cpu, 0);
     78}
     79
     80static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
     81{
     82	return vpa_call(H_VPA_REG_SLB, cpu, vpa);
     83}
     84
     85static inline long unregister_dtl(unsigned long cpu)
     86{
     87	return vpa_call(H_VPA_DEREG_DTL, cpu, 0);
     88}
     89
     90static inline long register_dtl(unsigned long cpu, unsigned long vpa)
     91{
     92	return vpa_call(H_VPA_REG_DTL, cpu, vpa);
     93}
     94
     95extern void vpa_init(int cpu);
     96
     97static inline long plpar_pte_enter(unsigned long flags,
     98		unsigned long hpte_group, unsigned long hpte_v,
     99		unsigned long hpte_r, unsigned long *slot)
    100{
    101	long rc;
    102	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    103
    104	rc = plpar_hcall(H_ENTER, retbuf, flags, hpte_group, hpte_v, hpte_r);
    105
    106	*slot = retbuf[0];
    107
    108	return rc;
    109}
    110
    111static inline long plpar_pte_remove(unsigned long flags, unsigned long ptex,
    112		unsigned long avpn, unsigned long *old_pteh_ret,
    113		unsigned long *old_ptel_ret)
    114{
    115	long rc;
    116	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    117
    118	rc = plpar_hcall(H_REMOVE, retbuf, flags, ptex, avpn);
    119
    120	*old_pteh_ret = retbuf[0];
    121	*old_ptel_ret = retbuf[1];
    122
    123	return rc;
    124}
    125
    126/* plpar_pte_remove_raw can be called in real mode. It calls plpar_hcall_raw */
    127static inline long plpar_pte_remove_raw(unsigned long flags, unsigned long ptex,
    128		unsigned long avpn, unsigned long *old_pteh_ret,
    129		unsigned long *old_ptel_ret)
    130{
    131	long rc;
    132	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    133
    134	rc = plpar_hcall_raw(H_REMOVE, retbuf, flags, ptex, avpn);
    135
    136	*old_pteh_ret = retbuf[0];
    137	*old_ptel_ret = retbuf[1];
    138
    139	return rc;
    140}
    141
    142static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
    143		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
    144{
    145	long rc;
    146	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    147
    148	rc = plpar_hcall(H_READ, retbuf, flags, ptex);
    149
    150	*old_pteh_ret = retbuf[0];
    151	*old_ptel_ret = retbuf[1];
    152
    153	return rc;
    154}
    155
    156/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
    157static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
    158		unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
    159{
    160	long rc;
    161	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    162
    163	rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
    164
    165	*old_pteh_ret = retbuf[0];
    166	*old_ptel_ret = retbuf[1];
    167
    168	return rc;
    169}
    170
    171/*
    172 * ptes must be 8*sizeof(unsigned long)
    173 */
    174static inline long plpar_pte_read_4(unsigned long flags, unsigned long ptex,
    175				    unsigned long *ptes)
    176
    177{
    178	long rc;
    179	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
    180
    181	rc = plpar_hcall9(H_READ, retbuf, flags | H_READ_4, ptex);
    182
    183	memcpy(ptes, retbuf, 8*sizeof(unsigned long));
    184
    185	return rc;
    186}
    187
    188/*
    189 * plpar_pte_read_4_raw can be called in real mode.
    190 * ptes must be 8*sizeof(unsigned long)
    191 */
    192static inline long plpar_pte_read_4_raw(unsigned long flags, unsigned long ptex,
    193					unsigned long *ptes)
    194
    195{
    196	long rc;
    197	unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
    198
    199	rc = plpar_hcall9_raw(H_READ, retbuf, flags | H_READ_4, ptex);
    200
    201	memcpy(ptes, retbuf, 8*sizeof(unsigned long));
    202
    203	return rc;
    204}
    205
    206static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
    207		unsigned long avpn)
    208{
    209	return plpar_hcall_norets(H_PROTECT, flags, ptex, avpn);
    210}
    211
    212static inline long plpar_resize_hpt_prepare(unsigned long flags,
    213					    unsigned long shift)
    214{
    215	return plpar_hcall_norets(H_RESIZE_HPT_PREPARE, flags, shift);
    216}
    217
    218static inline long plpar_resize_hpt_commit(unsigned long flags,
    219					   unsigned long shift)
    220{
    221	return plpar_hcall_norets(H_RESIZE_HPT_COMMIT, flags, shift);
    222}
    223
    224static inline long plpar_tce_get(unsigned long liobn, unsigned long ioba,
    225		unsigned long *tce_ret)
    226{
    227	long rc;
    228	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    229
    230	rc = plpar_hcall(H_GET_TCE, retbuf, liobn, ioba);
    231
    232	*tce_ret = retbuf[0];
    233
    234	return rc;
    235}
    236
    237static inline long plpar_tce_put(unsigned long liobn, unsigned long ioba,
    238		unsigned long tceval)
    239{
    240	return plpar_hcall_norets(H_PUT_TCE, liobn, ioba, tceval);
    241}
    242
    243static inline long plpar_tce_put_indirect(unsigned long liobn,
    244		unsigned long ioba, unsigned long page, unsigned long count)
    245{
    246	return plpar_hcall_norets(H_PUT_TCE_INDIRECT, liobn, ioba, page, count);
    247}
    248
    249static inline long plpar_tce_stuff(unsigned long liobn, unsigned long ioba,
    250		unsigned long tceval, unsigned long count)
    251{
    252	return plpar_hcall_norets(H_STUFF_TCE, liobn, ioba, tceval, count);
    253}
    254
    255/* Set various resource mode parameters */
    256static inline long plpar_set_mode(unsigned long mflags, unsigned long resource,
    257		unsigned long value1, unsigned long value2)
    258{
    259	return plpar_hcall_norets(H_SET_MODE, mflags, resource, value1, value2);
    260}
    261
    262/*
    263 * Enable relocation on exceptions on this partition
    264 *
    265 * Note: this call has a partition wide scope and can take a while to complete.
    266 * If it returns H_LONG_BUSY_* it should be retried periodically until it
    267 * returns H_SUCCESS.
    268 */
    269static inline long enable_reloc_on_exceptions(void)
    270{
    271	/* mflags = 3: Exceptions at 0xC000000000004000 */
    272	return plpar_set_mode(3, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0);
    273}
    274
    275/*
    276 * Disable relocation on exceptions on this partition
    277 *
    278 * Note: this call has a partition wide scope and can take a while to complete.
    279 * If it returns H_LONG_BUSY_* it should be retried periodically until it
    280 * returns H_SUCCESS.
    281 */
    282static inline long disable_reloc_on_exceptions(void) {
    283	return plpar_set_mode(0, H_SET_MODE_RESOURCE_ADDR_TRANS_MODE, 0, 0);
    284}
    285
    286/*
    287 * Take exceptions in big endian mode on this partition
    288 *
    289 * Note: this call has a partition wide scope and can take a while to complete.
    290 * If it returns H_LONG_BUSY_* it should be retried periodically until it
    291 * returns H_SUCCESS.
    292 */
    293static inline long enable_big_endian_exceptions(void)
    294{
    295	/* mflags = 0: big endian exceptions */
    296	return plpar_set_mode(0, H_SET_MODE_RESOURCE_LE, 0, 0);
    297}
    298
    299/*
    300 * Take exceptions in little endian mode on this partition
    301 *
    302 * Note: this call has a partition wide scope and can take a while to complete.
    303 * If it returns H_LONG_BUSY_* it should be retried periodically until it
    304 * returns H_SUCCESS.
    305 */
    306static inline long enable_little_endian_exceptions(void)
    307{
    308	/* mflags = 1: little endian exceptions */
    309	return plpar_set_mode(1, H_SET_MODE_RESOURCE_LE, 0, 0);
    310}
    311
    312static inline long plpar_set_ciabr(unsigned long ciabr)
    313{
    314	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_CIABR, ciabr, 0);
    315}
    316
    317static inline long plpar_set_watchpoint0(unsigned long dawr0, unsigned long dawrx0)
    318{
    319	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR0, dawr0, dawrx0);
    320}
    321
    322static inline long plpar_set_watchpoint1(unsigned long dawr1, unsigned long dawrx1)
    323{
    324	return plpar_set_mode(0, H_SET_MODE_RESOURCE_SET_DAWR1, dawr1, dawrx1);
    325}
    326
    327static inline long plpar_signal_sys_reset(long cpu)
    328{
    329	return plpar_hcall_norets(H_SIGNAL_SYS_RESET, cpu);
    330}
    331
    332static inline long plpar_get_cpu_characteristics(struct h_cpu_char_result *p)
    333{
    334	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
    335	long rc;
    336
    337	rc = plpar_hcall(H_GET_CPU_CHARACTERISTICS, retbuf);
    338	if (rc == H_SUCCESS) {
    339		p->character = retbuf[0];
    340		p->behaviour = retbuf[1];
    341	}
    342
    343	return rc;
    344}
    345
    346/*
    347 * Wrapper to H_RPT_INVALIDATE hcall that handles return values appropriately
    348 *
    349 * - Returns H_SUCCESS on success
    350 * - For H_BUSY return value, we retry the hcall.
    351 * - For any other hcall failures, attempt a full flush once before
    352 *   resorting to BUG().
    353 *
    354 * Note: This hcall is expected to fail only very rarely. The correct
    355 * error recovery of killing the process/guest will be eventually
    356 * needed.
    357 */
    358static inline long pseries_rpt_invalidate(u32 pid, u64 target, u64 type,
    359					  u64 page_sizes, u64 start, u64 end)
    360{
    361	long rc;
    362	unsigned long all;
    363
    364	while (true) {
    365		rc = plpar_hcall_norets(H_RPT_INVALIDATE, pid, target, type,
    366					page_sizes, start, end);
    367		if (rc == H_BUSY) {
    368			cpu_relax();
    369			continue;
    370		} else if (rc == H_SUCCESS)
    371			return rc;
    372
    373		/* Flush request failed, try with a full flush once */
    374		if (type & H_RPTI_TYPE_NESTED)
    375			all = H_RPTI_TYPE_NESTED | H_RPTI_TYPE_NESTED_ALL;
    376		else
    377			all = H_RPTI_TYPE_ALL;
    378retry:
    379		rc = plpar_hcall_norets(H_RPT_INVALIDATE, pid, target,
    380					all, page_sizes, 0, -1UL);
    381		if (rc == H_BUSY) {
    382			cpu_relax();
    383			goto retry;
    384		} else if (rc == H_SUCCESS)
    385			return rc;
    386
    387		BUG();
    388	}
    389}
    390
    391#else /* !CONFIG_PPC_PSERIES */
    392
    393static inline long plpar_set_ciabr(unsigned long ciabr)
    394{
    395	return 0;
    396}
    397
    398static inline long plpar_pte_read_4(unsigned long flags, unsigned long ptex,
    399				    unsigned long *ptes)
    400{
    401	return 0;
    402}
    403
    404static inline long pseries_rpt_invalidate(u32 pid, u64 target, u64 type,
    405					  u64 page_sizes, u64 start, u64 end)
    406{
    407	return 0;
    408}
    409
    410#endif /* CONFIG_PPC_PSERIES */
    411
    412#endif /* _ASM_POWERPC_PLPAR_WRAPPERS_H */