xref: /plan9-contrib/sys/src/cmd/aux/vmware/msgchan.c (revision 06d2afa6aa61b39f2ff8184391f0458258bcc86a)
1 #include "all.h"
2 #include <fcall.h>
3 #include <thread.h>
4 #include <9p.h>	/* for emalloc9p */
5 
6 enum
7 {
8 	/* high bits of u.cx */
9 	CmdOpen		= 0x00,
10 	CmdSendsize	= 0x01,
11 	CmdSenddata	= 0x02,
12 	CmdRecvsize	= 0x03,
13 	CmdRecvdata	= 0x04,
14 	CmdRecvstatus	= 0x05,
15 	CmdClose		= 0x06,
16 
17 	StatSuccess	= 0x0001,		/* request succeeded */
18 	StatHavedata	= 0x0002,		/* vmware has message available */
19 	StatClosed	= 0x0004,		/* channel got closed */
20 	StatUnsent	= 0x0008,		/* vmware removed message before it got delivered */
21 	StatChkpt		= 0x0010,		/* checkpoint occurred */
22 	StatPoweroff	= 0x0020,		/* underlying device is powering off */
23 };
24 
25 
26 Msgchan*
openmsg(ulong proto)27 openmsg(ulong proto)
28 {
29 	Msgchan *c;
30 	Ureg u;
31 
32 	memset(&u, 0, sizeof u);
33 	u.cx = (CmdOpen<<16) | BackMessage;
34 	u.bx = proto;
35 
36 	backdoor(&u, 0);
37 
38 fprint(2, "msgopen %.8lux\n", u.cx);
39 	if(!(u.cx & (StatSuccess<<16))){
40 		fprint(2, "message %.8lux\n", u.cx);
41 		werrstr("unable to open message channel (%.8lux)", u.cx);
42 		return nil;
43 	}
44 
45 	c = emalloc9p(sizeof(*c));
46 	c->id = u.dx>>16;
47 	return c;
48 }
49 
50 enum
51 {
52 	Ok = 0,
53 	ErrBad = -1,
54 	ErrChkpt = -2,
55 };
56 
57 static int
sendpiece(Msgchan * c,int ty,ulong a)58 sendpiece(Msgchan *c, int ty, ulong a)
59 {
60 	Ureg u;
61 
62 	memset(&u, 0, sizeof u);
63 	u.cx = (ty<<16) | BackMessage;
64 	u.dx = c->id<<16;
65 	u.bx = a;
66 
67 	backdoor(&u, 0);
68 
69 	if(!(u.cx & (StatSuccess<<16))){
70 fprint(2, "cmd %x failed\n", ty);
71 		if(u.cx & (StatChkpt<<16))
72 			return ErrChkpt;
73 		return ErrBad;
74 	}
75 	return 0;
76 }
77 
78 int
sendmsg(Msgchan * c,void * a,int n)79 sendmsg(Msgchan *c, void *a, int n)
80 {
81 	int i, m, e, left;
82 	uchar *p;
83 	ulong v;
84 
85 Again:
86 	v = n;
87 	if(sendpiece(c, CmdSendsize, v) < 0)
88 		return -1;
89 
90 	p = a;
91 	left = n;
92 	while(left > 0){
93 		m = left;
94 		if(m > 4)
95 			m = 4;
96 		v = 0;
97 		for(i=0; i<m; i++)
98 			v |= *p++ << (8*i);
99 		if((e=sendpiece(c, CmdSenddata, v)) < 0){
100 			if(e == -2)
101 				goto Again;
102 			return -1;
103 		}
104 		left -= m;
105 	}
106 	return 0;
107 }
108 
109 static int
recvpiece(Msgchan * c,int ty,ulong * stat,ulong * a)110 recvpiece(Msgchan *c, int ty, ulong *stat, ulong *a)
111 {
112 	Ureg u;
113 
114 fprint(2, "recvpiece %d %d\n", c->id, ty);
115 	memset(&u, 0, sizeof u);
116 	u.cx = (ty<<16) | BackMessage;
117 	u.bx = StatSuccess;
118 	u.dx = c->id<<16;
119 
120 	backdoor(&u, 0);
121 
122 	if(!(u.cx & (StatSuccess<<16))){
123 fprint(2, "no success %lux\n", u.cx);
124 		if(u.cx & (StatChkpt<<16))
125 			return ErrChkpt;
126 		return ErrBad;
127 	}
128 	*stat = u.cx;
129 	if(ty == CmdRecvsize && !(u.cx&(StatHavedata<<16))){
130 fprint(2, "poll got no data\n");
131 		return 0;
132 	}
133 
134 	if(ty != CmdRecvstatus && (u.dx>>16) != ty-2){
135 fprint(2, "got wrong answer! %lux\n", u.dx);
136 		werrstr("protocol error");
137 		return ErrBad;
138 	}
139 	*a = u.bx;
140 fprint(2, "got %lux\n", *a);
141 	return 0;
142 }
143 
144 static void
signalerror(Msgchan * c,int ty)145 signalerror(Msgchan *c, int ty)
146 {
147 	Ureg u;
148 
149 	memset(&u, 0, sizeof u);
150 	u.cx = (ty<<16) | BackMessage;
151 	u.dx = c->id<<16;
152 	u.bx = 0;
153 	backdoor(&u, 0);
154 }
155 
156 int
recvmsg(Msgchan * c,void ** pp)157 recvmsg(Msgchan *c, void **pp)
158 {
159 	int left;
160 	ulong v, stat, tot;
161 	uchar *p;
162 
163 Top:
164 	if(recvpiece(c, CmdRecvsize, &stat, &tot) < 0)
165 		return -1;
166 
167 	if(!(stat & (StatHavedata<<16)))
168 		return 0;
169 
170 	free(c->a);
171 	c->a = emalloc9p(tot+5);
172 	c->na = tot;
173 	p = c->a;		/* NUL terminate for callers */
174 
175 	left = tot;
176 	while(left > 0){
177 		switch(recvpiece(c, CmdRecvdata, &stat, &v)){
178 		case ErrChkpt:
179 			goto Top;
180 		case ErrBad:
181 			signalerror(c, CmdRecvdata);
182 			return -1;
183 		}
184 		*(uint*)p = v;
185 		p += 4;
186 		left -= 4;
187 	}
188 	((char*)c->a)[tot] = '\0';
189 
190 	switch(recvpiece(c, CmdRecvstatus, &stat, &v)){
191 	case ErrChkpt:
192 		goto Top;
193 	case ErrBad:
194 		/* BUG: signal receipt of error */
195 		signalerror(c, CmdRecvstatus);
196 		return -1;
197 	}
198 
199 	*pp = c->a;
200 	return tot;
201 }
202 
203 int
closemsg(Msgchan * c)204 closemsg(Msgchan *c)
205 {
206 	Ureg u;
207 
208 	memset(&u, 0, sizeof u);
209 
210 	u.cx = (CmdClose<<16) | BackMessage;
211 	u.dx = c->id;
212 
213 	backdoor(&u, 0);
214 
215 	if(!(u.cx & (StatSuccess<<16))){
216 		werrstr("unable to close message channel");
217 		return -1;
218 	}
219 
220 	free(c->a);
221 	c->a = nil;
222 	free(c);
223 	return 0;
224 }
225