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* 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 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 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 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 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 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 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