1 // SPDX-License-Identifier: MIT
2 /* Copyright (C) 2006-2017 Oracle Corporation */
3 
4 #include <linux/vbox_err.h>
5 #include "vbox_drv.h"
6 #include "vboxvideo_guest.h"
7 #include "vboxvideo_vbe.h"
8 #include "hgsmi_channels.h"
9 #include "hgsmi_ch_setup.h"
10 
11 /**
12  * Inform the host of the location of the host flags in VRAM via an HGSMI cmd.
13  * Return: 0 or negative errno value.
14  * @ctx:        The context of the guest heap to use.
15  * @location:   The offset chosen for the flags within guest VRAM.
16  */
17 int hgsmi_report_flags_location(struct gen_pool *ctx, u32 location)
18 {
19 	struct hgsmi_buffer_location *p;
20 
21 	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_HGSMI,
22 			       HGSMI_CC_HOST_FLAGS_LOCATION);
23 	if (!p)
24 		return -ENOMEM;
25 
26 	p->buf_location = location;
27 	p->buf_len = sizeof(struct hgsmi_host_flags);
28 
29 	hgsmi_buffer_submit(ctx, p);
30 	hgsmi_buffer_free(ctx, p);
31 
32 	return 0;
33 }
34 
35 /**
36  * Notify the host of HGSMI-related guest capabilities via an HGSMI command.
37  * Return: 0 or negative errno value.
38  * @ctx:        The context of the guest heap to use.
39  * @caps:       The capabilities to report, see vbva_caps.
40  */
41 int hgsmi_send_caps_info(struct gen_pool *ctx, u32 caps)
42 {
43 	struct vbva_caps *p;
44 
45 	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA, VBVA_INFO_CAPS);
46 	if (!p)
47 		return -ENOMEM;
48 
49 	p->rc = VERR_NOT_IMPLEMENTED;
50 	p->caps = caps;
51 
52 	hgsmi_buffer_submit(ctx, p);
53 
54 	WARN_ON_ONCE(p->rc < 0);
55 
56 	hgsmi_buffer_free(ctx, p);
57 
58 	return 0;
59 }
60 
61 int hgsmi_test_query_conf(struct gen_pool *ctx)
62 {
63 	u32 value = 0;
64 	int ret;
65 
66 	ret = hgsmi_query_conf(ctx, U32_MAX, &value);
67 	if (ret)
68 		return ret;
69 
70 	return value == U32_MAX ? 0 : -EIO;
71 }
72 
73 /**
74  * Query the host for an HGSMI configuration parameter via an HGSMI command.
75  * Return: 0 or negative errno value.
76  * @ctx:        The context containing the heap used.
77  * @index:      The index of the parameter to query.
78  * @value_ret:  Where to store the value of the parameter on success.
79  */
80 int hgsmi_query_conf(struct gen_pool *ctx, u32 index, u32 *value_ret)
81 {
82 	struct vbva_conf32 *p;
83 
84 	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
85 			       VBVA_QUERY_CONF32);
86 	if (!p)
87 		return -ENOMEM;
88 
89 	p->index = index;
90 	p->value = U32_MAX;
91 
92 	hgsmi_buffer_submit(ctx, p);
93 
94 	*value_ret = p->value;
95 
96 	hgsmi_buffer_free(ctx, p);
97 
98 	return 0;
99 }
100 
101 /**
102  * Pass the host a new mouse pointer shape via an HGSMI command.
103  * Return: 0 or negative errno value.
104  * @ctx:        The context containing the heap to be used.
105  * @flags:      Cursor flags.
106  * @hot_x:      Horizontal position of the hot spot.
107  * @hot_y:      Vertical position of the hot spot.
108  * @width:      Width in pixels of the cursor.
109  * @height:     Height in pixels of the cursor.
110  * @pixels:     Pixel data, @see VMMDevReqMousePointer for the format.
111  * @len:        Size in bytes of the pixel data.
112  */
113 int hgsmi_update_pointer_shape(struct gen_pool *ctx, u32 flags,
114 			       u32 hot_x, u32 hot_y, u32 width, u32 height,
115 			       u8 *pixels, u32 len)
116 {
117 	struct vbva_mouse_pointer_shape *p;
118 	u32 pixel_len = 0;
119 	int rc;
120 
121 	if (flags & VBOX_MOUSE_POINTER_SHAPE) {
122 		/*
123 		 * Size of the pointer data:
124 		 * sizeof (AND mask) + sizeof (XOR_MASK)
125 		 */
126 		pixel_len = ((((width + 7) / 8) * height + 3) & ~3) +
127 			 width * 4 * height;
128 		if (pixel_len > len)
129 			return -EINVAL;
130 
131 		/*
132 		 * If shape is supplied, then always create the pointer visible.
133 		 * See comments in 'vboxUpdatePointerShape'
134 		 */
135 		flags |= VBOX_MOUSE_POINTER_VISIBLE;
136 	}
137 
138 	p = hgsmi_buffer_alloc(ctx, sizeof(*p) + pixel_len, HGSMI_CH_VBVA,
139 			       VBVA_MOUSE_POINTER_SHAPE);
140 	if (!p)
141 		return -ENOMEM;
142 
143 	p->result = VINF_SUCCESS;
144 	p->flags = flags;
145 	p->hot_X = hot_x;
146 	p->hot_y = hot_y;
147 	p->width = width;
148 	p->height = height;
149 	if (pixel_len)
150 		memcpy(p->data, pixels, pixel_len);
151 
152 	hgsmi_buffer_submit(ctx, p);
153 
154 	switch (p->result) {
155 	case VINF_SUCCESS:
156 		rc = 0;
157 		break;
158 	case VERR_NO_MEMORY:
159 		rc = -ENOMEM;
160 		break;
161 	case VERR_NOT_SUPPORTED:
162 		rc = -EBUSY;
163 		break;
164 	default:
165 		rc = -EINVAL;
166 	}
167 
168 	hgsmi_buffer_free(ctx, p);
169 
170 	return rc;
171 }
172 
173 /**
174  * Report the guest cursor position.  The host may wish to use this information
175  * to re-position its own cursor (though this is currently unlikely).  The
176  * current host cursor position is returned.
177  * Return: 0 or negative errno value.
178  * @ctx:              The context containing the heap used.
179  * @report_position:  Are we reporting a position?
180  * @x:                Guest cursor X position.
181  * @y:                Guest cursor Y position.
182  * @x_host:           Host cursor X position is stored here.  Optional.
183  * @y_host:           Host cursor Y position is stored here.  Optional.
184  */
185 int hgsmi_cursor_position(struct gen_pool *ctx, bool report_position,
186 			  u32 x, u32 y, u32 *x_host, u32 *y_host)
187 {
188 	struct vbva_cursor_position *p;
189 
190 	p = hgsmi_buffer_alloc(ctx, sizeof(*p), HGSMI_CH_VBVA,
191 			       VBVA_CURSOR_POSITION);
192 	if (!p)
193 		return -ENOMEM;
194 
195 	p->report_position = report_position;
196 	p->x = x;
197 	p->y = y;
198 
199 	hgsmi_buffer_submit(ctx, p);
200 
201 	*x_host = p->x;
202 	*y_host = p->y;
203 
204 	hgsmi_buffer_free(ctx, p);
205 
206 	return 0;
207 }
208