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