00001 #ifndef ROSE_ETHER_H
00002 #define ROSE_ETHER_H
00003
00004 #ifdef ROSE_USE_ETHER
00005
00006 extern "C" {
00007 #include <sys/mman.h>
00008 #include <xenctrl.h>
00009 #include <xen/domctl.h>
00010 #include <xen/hvm/ether.h>
00011 }
00012
00013 #include <sys/mman.h>
00014
00015 class Ether {
00016 private:
00017 Ether() {}
00018
00019 public:
00020 struct Exception {
00021 Exception(const std::string &mesg)
00022 : mesg(mesg) {}
00023 std::string mesg;
00024 };
00025
00027 Ether(domid_t dom)
00028 : xc_iface(-1), xc_event_iface(-1), dom(0), shared_page_mfn(0), shared_page(NULL), event_port(-1) {
00029
00030 if ((xc_iface = xc_interface_open())<0)
00031 throw Exception("cannot contact Xen hypervisor");
00032 if ((xc_event_iface = xc_evtchn_open())<0)
00033 throw Exception("cannot open event channel");
00034
00035 CmdInit cmd;
00036 domctl(cmd, dom);
00037 this->dom = dom;
00038 shared_page_mfn = cmd.u.ether.comm.shared_page_mfn;
00039
00040
00041
00042 shared_page = (volatile unsigned char*)xc_map_foreign_range(xc_iface, DOMID_XEN, getpagesize(),
00043 PROT_READ|PROT_WRITE, shared_page_mfn);
00044 if (!shared_page)
00045 throw("cannot map shared page");
00046
00047
00048
00049
00050 event_port = xc_evtchn_bind_interdomain(xc_event_iface, DOMID_SELF, cmd.u.ether.comm.event_channel_port);
00051 if (event_port<0)
00052 throw("cannot bind ether event port");
00053
00054
00055 printf("After init:\n");
00056 printf(" domain: %d\n", dom);
00057 printf(" xc_iface: %d\n", xc_iface);
00058 printf(" xc_event_iface: %d\n", xc_event_iface);
00059 printf(" shared_page: %p\n", shared_page);
00060 printf(" shared_page_mfn: 0x%lx\n", shared_page_mfn);
00061 printf(" event_channel_port: %d\n", cmd.u.ether.comm.event_channel_port);
00062 printf(" event_port: %u\n", event_port);
00063 }
00064
00066 ~Ether() {
00067 if (shared_page!=NULL) {
00068 domctl(CmdTerminate());
00069 xc_domain_unpause(xc_iface, dom);
00070 }
00071 if (event_port>=0) {
00072 xc_evtchn_unbind(xc_event_iface, event_port);
00073 event_port = -1;
00074 }
00075 if (shared_page!=NULL) {
00076 if (is_lock_held())
00077 release_lock();
00078 munmap((void*)shared_page, getpagesize());
00079 shared_page = NULL;
00080 shared_page_mfn = 0;
00081 }
00082 if (xc_event_iface>=0) {
00083 xc_evtchn_close(xc_event_iface);
00084 xc_event_iface = -1;
00085 }
00086 if (xc_iface) {
00087 xc_interface_close(xc_iface);
00088 xc_iface = -1;
00089 }
00090 }
00091
00093 void readguest(rose_addr_t va, unsigned char *buffer, size_t size) {
00094 domctl(CmdReadGuest(va, buffer, size));
00095 }
00096
00099 void set_single_step(bool status) {
00100 domctl(CmdSingleStep(status));
00101 }
00102
00105 void set_single_step_notify(bool status) {
00106 domctl(CmdSingleStepNotify(status));
00107 }
00108
00110 void set_memwrite_notify(bool status) {
00111 domctl(CmdMemwriteNotify(status));
00112 }
00113
00115 void set_unpack_notify(bool status) {
00116 domctl(CmdUnpackNotify(status));
00117 }
00118
00122 void set_sysenter(bool new_eip) {
00123 domctl(CmdSysenter(new_eip));
00124 }
00125
00127 void add_name_filter(const std::string &name) {
00128 domctl(CmdAddName(name));
00129 }
00130
00131
00132 void add_cr3_filter(rose_addr_t cr3) {
00133 domctl(CmdAddCR3(cr3));
00134 }
00135
00138 bool is_lock_held() {
00139 if (shared_page==NULL)
00140 throw Exception("no shared page");
00141 return *(volatile uint32_t*)shared_page ? true : false;
00142 }
00143
00147 void release_lock() {
00148 if (shared_page==NULL)
00149 throw Exception("no shared page");
00150 if (!is_lock_held())
00151 throw Exception("shared page lock is not set\n");
00152 *(volatile uint32_t*)shared_page = 0;
00153 }
00154
00158 int next_event() {
00159 if (shared_page==NULL)
00160 throw Exception("no shared page");
00161 while (1) {
00162 if (xc_evtchn_pending(xc_event_iface)!=event_port) {
00163 xc_domain_unpause(xc_iface, dom);
00164 } else if (xc_evtchn_unmask(xc_event_iface, event_port)<0) {
00165 throw Exception("cannot unmask ether event");
00166 } else if (!is_lock_held()) {
00167 xc_domain_unpause(xc_iface, dom);
00168 throw Exception("ether event but shared page lock is clear");
00169 }
00170
00171 return ((volatile uint32_t*)shared_page)[1];
00172 }
00173 }
00174
00176 const void *event_data() {
00177 if (!is_lock_held())
00178 throw Exception("shared page lock is not set");
00179 if (!shared_page)
00180 throw Exception("no shared page");
00181 return (const void*)(shared_page+8);
00182 }
00183
00186 void resume() {
00187 if (is_lock_held())
00188 release_lock();
00189 xc_domain_unpause(xc_iface, dom);
00190 }
00191
00192 private:
00193 struct CmdInit: public xen_domctl {
00194 CmdInit() {
00195 u.ether.command_code = XEN_DOMCTL_ETHER_INIT;
00196 memset(&u.ether.comm, 0, sizeof(u.ether.comm));
00197 }
00198 };
00199
00200 struct CmdTerminate: public xen_domctl {
00201 CmdTerminate() {
00202 u.ether.command_code = XEN_DOMCTL_ETHER_TERMINATE;
00203 }
00204 };
00205
00206 struct CmdReadGuest: public xen_domctl {
00207 CmdReadGuest(rose_addr_t va, void *buffer, size_t size) {
00208 u.ether.command_code = XEN_DOMCTL_ETHER_READ_GUEST;
00209 u.ether.guest_va = va;
00210 u.ether.guest_buffer = (unsigned char*)buffer;
00211 u.ether.data_length = size;
00212
00213 memset(buffer, 0, size);
00214 }
00215 };
00216
00217 struct CmdSingleStep: public xen_domctl {
00218 CmdSingleStep(bool status) {
00219 u.ether.command_code = XEN_DOMCTL_ETHER_SINGLE_STEP;
00220 u.ether.on_or_off = status;
00221 }
00222 };
00223
00224 struct CmdSingleStepNotify: public xen_domctl {
00225 CmdSingleStepNotify(bool status) {
00226 u.ether.command_code = XEN_DOMCTL_ETHER_SS_DETECT;
00227 u.ether.on_or_off = status;
00228 }
00229 };
00230
00231 struct CmdMemwriteNotify: public xen_domctl {
00232 CmdMemwriteNotify(bool status) {
00233 u.ether.command_code = XEN_DOMCTL_ETHER_MEMWRITE;
00234 u.ether.on_or_off = status;
00235 }
00236 };
00237
00238 struct CmdUnpackNotify: public xen_domctl {
00239 CmdUnpackNotify(bool status) {
00240 u.ether.command_code = XEN_DOMCTL_ETHER_UNPACK;
00241 u.ether.on_or_off = status;
00242 }
00243 };
00244
00245 struct CmdSysenter: public xen_domctl {
00246 CmdSysenter(rose_addr_t eip) {
00247 u.ether.command_code = XEN_DOMCTL_ETHER_SET_SYSENTER;
00248 u.ether.sysenter_cs = 0;
00249 u.ether.sysenter_eip = eip;
00250 }
00251 };
00252
00253 struct CmdAddCR3: public xen_domctl {
00254 CmdAddCR3(rose_addr_t cr3) {
00255 u.ether.command_code = XEN_DOMCTL_ETHER_ADD_CR3;
00256 u.ether.cr3_value = cr3;
00257 }
00258 };
00259
00260 struct CmdAddName: public xen_domctl {
00261 CmdAddName(const std::string &name) {
00262 u.ether.command_code = XEN_DOMCTL_ETHER_ADD_NAME;
00263 u.ether.data_length = name.size() + 1;
00264 u.ether.guest_buffer = (unsigned char*)(name.c_str());
00265 }
00266 };
00267
00268 bool connected() {
00269 return xc_iface>=0 && dom>0;
00270 }
00271
00272
00273
00274
00275 void domctl(const xen_domctl &cmd, domid_t dom=0) {
00276 domctl(const_cast<xen_domctl*>(&cmd), dom);
00277 }
00278 void domctl(xen_domctl &cmd, domid_t dom=0) {
00279 domctl(&cmd, dom);
00280 }
00281 void domctl(xen_domctl *cmd, domid_t dom=0) {
00282 if (connected()) {
00283 if (dom>0 && dom!=this->dom)
00284 throw Exception("contradicting domain IDs");
00285 dom = this->dom;
00286 } else if (dom<=0) {
00287 throw Exception("not connected");
00288 }
00289
00290 cmd->domain = dom;
00291 cmd->cmd = XEN_DOMCTL_ether;
00292 int result = xc_domctl(xc_iface, cmd);
00293 if (result<0) {
00294 char buf[256];
00295 sprintf(buf, "xc_domctl(request=%u) failed", cmd->u.ether.command_code);
00296 throw Exception(buf);
00297 }
00298 }
00299
00300 private:
00301 int xc_iface;
00302 int xc_event_iface;
00303 domid_t dom;
00305 rose_addr_t shared_page_mfn;
00306 volatile unsigned char *shared_page;
00308 evtchn_port_t event_port;
00309 };
00310
00311 #endif
00312 #endif