blob: 67f63b76dc18b560ecfc7c521d52d6dee1230d95 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Ultravisor Interfaces
4 *
5 * Copyright IBM Corp. 2019
6 *
7 * Author(s):
8 * Vasily Gorbik <gor@linux.ibm.com>
9 * Janosch Frank <frankja@linux.ibm.com>
10 */
11#ifndef _ASM_S390_UV_H
12#define _ASM_S390_UV_H
13
14#include <linux/types.h>
15#include <linux/errno.h>
16#include <linux/bug.h>
17#include <asm/page.h>
18
19#define UVC_RC_EXECUTED 0x0001
20#define UVC_RC_INV_CMD 0x0002
21#define UVC_RC_INV_STATE 0x0003
22#define UVC_RC_INV_LEN 0x0005
23#define UVC_RC_NO_RESUME 0x0007
24
25#define UVC_CMD_QUI 0x0001
26#define UVC_CMD_SET_SHARED_ACCESS 0x1000
27#define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001
28
29/* Bits in installed uv calls */
30enum uv_cmds_inst {
31 BIT_UVC_CMD_QUI = 0,
32 BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
33 BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
34};
35
36struct uv_cb_header {
37 u16 len;
38 u16 cmd; /* Command Code */
39 u16 rc; /* Response Code */
40 u16 rrc; /* Return Reason Code */
41} __packed __aligned(8);
42
43struct uv_cb_qui {
44 struct uv_cb_header header;
45 u64 reserved08;
46 u64 inst_calls_list[4];
47 u64 reserved30[15];
48} __packed __aligned(8);
49
50struct uv_cb_share {
51 struct uv_cb_header header;
52 u64 reserved08[3];
53 u64 paddr;
54 u64 reserved28;
55} __packed __aligned(8);
56
57static inline int uv_call(unsigned long r1, unsigned long r2)
58{
59 int cc;
60
61 asm volatile(
62 "0: .insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
63 " brc 3,0b\n"
64 " ipm %[cc]\n"
65 " srl %[cc],28\n"
66 : [cc] "=d" (cc)
67 : [r1] "a" (r1), [r2] "a" (r2)
68 : "memory", "cc");
69 return cc;
70}
71
72#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
73extern int prot_virt_guest;
74
75static inline int is_prot_virt_guest(void)
76{
77 return prot_virt_guest;
78}
79
80static inline int share(unsigned long addr, u16 cmd)
81{
82 struct uv_cb_share uvcb = {
83 .header.cmd = cmd,
84 .header.len = sizeof(uvcb),
85 .paddr = addr
86 };
87
88 if (!is_prot_virt_guest())
89 return -ENOTSUPP;
90 /*
91 * Sharing is page wise, if we encounter addresses that are
92 * not page aligned, we assume something went wrong. If
93 * malloced structs are passed to this function, we could leak
94 * data to the hypervisor.
95 */
96 BUG_ON(addr & ~PAGE_MASK);
97
98 if (!uv_call(0, (u64)&uvcb))
99 return 0;
100 pr_err("%s UVC failed (rc: 0x%x, rrc: 0x%x), possible hypervisor bug.\n",
101 uvcb.header.cmd == UVC_CMD_SET_SHARED_ACCESS ? "Share" : "Unshare",
102 uvcb.header.rc, uvcb.header.rrc);
103 panic("System security cannot be guaranteed unless the system panics now.\n");
104}
105
106/*
107 * Guest 2 request to the Ultravisor to make a page shared with the
108 * hypervisor for IO.
109 *
110 * @addr: Real or absolute address of the page to be shared
111 */
112static inline int uv_set_shared(unsigned long addr)
113{
114 return share(addr, UVC_CMD_SET_SHARED_ACCESS);
115}
116
117/*
118 * Guest 2 request to the Ultravisor to make a page unshared.
119 *
120 * @addr: Real or absolute address of the page to be unshared
121 */
122static inline int uv_remove_shared(unsigned long addr)
123{
124 return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
125}
126
127void uv_query_info(void);
128#else
129#define is_prot_virt_guest() 0
130static inline int uv_set_shared(unsigned long addr) { return 0; }
131static inline int uv_remove_shared(unsigned long addr) { return 0; }
132static inline void uv_query_info(void) {}
133#endif
134
135#endif /* _ASM_S390_UV_H */