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