// // Called to create the network connection. // static VMIOS_INTERCEPT_FN(netInit) { object->domain = vmirtGetProcessorDataDomain(processor); Uns32 prefixStringAddr; Uns32 localNetAddr; getArg(processor, object, 0, &object->diagLevel); getArg(processor, object, 1, &object->packets); getArg(processor, object, 2, &prefixStringAddr); getArg(processor, object, 3, &localNetAddr); object->pollCount = 0; const char *tftp_path = NULL; if(prefixStringAddr) { tftp_path = vmirtGetString(object->domain, prefixStringAddr); if(DIAG_LOW) { vmiMessage("I", PREFIX, "local tftp server is active. Root directory is '%s'", object->tftpPath ); } } const char *localNet = localNetAddr ? vmirtGetString(object->domain, localNetAddr) : "10.0.2.0"; char vhostname[256]; vhostname[0] = 0; //gethostname(vhostname, sizeof(vhostname)); const char *bootfile = NULL; const char *vnetmask = NULL; const char *vdhcp_start = NULL; const char *vnameserver = NULL; const char *vhost = NULL; Bool restricted = False; object->slirp = net_slirp_init( restricted, localNet, vnetmask, vhost, vhostname, tftp_path, bootfile, vdhcp_start, vnameserver, object ); if (!object->slirp) { vmiMessage("F", PREFIX, "Unable to start networking"); } }
// // ESR[EC] = 00001; ESR[W] = isWord; ESR[S] = isWrite; ESR[Rx] = rD // static void machineAlignError(vmiProcessorP processor, Uns32 bytes, Uns32 rDidx, Uns32 isWrite) { microblazeP microblaze = (microblazeP)processor; microblaze->SPR_ESR.reg = 0x0; microblaze->SPR_ESR.bits.EC = UNALIGNED_DATA_ACCESS; microblaze->exception = microblaze_E_UNALIGNED_DATA_ACCESS; switch (bytes) { case 4: microblaze->SPR_ESR.bits_ESS_EC_00001.W = 1; break; case 2: case 1: microblaze->SPR_ESR.bits_ESS_EC_00001.W = 0; break; default: vmiMessage("F", "machineAlignError", "%s bytes=%d", (isWrite ? "Write" : "Read"), bytes); /* no break */ } microblaze->SPR_ESR.bits_ESS_EC_00001.S = isWrite; microblaze->SPR_ESR.bits_ESS_EC_00001.Rx = rDidx; // // Call the general Hardware Exception routine // nonmmuException(microblaze); }
static VMIOS_INTERCEPT_FN(netPoll) { u_int timeMS; getArg(processor, object, 0, &timeMS); if(DIAG_HIGH) { vmiMessage("I", PREFIX, "netPoll #" FMT_64d " at %d ***********", object->pollCount, timeMS); } object->pollCount++; int nfds = -1; Slirp *slirp = object->slirp; FD_ZERO(&slirp->rfds); FD_ZERO(&slirp->wfds); FD_ZERO(&slirp->xfds); slirp_select_fill(slirp, &nfds, &slirp->rfds, &slirp->wfds, &slirp->xfds); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; int r = recSelectSocket(nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv); slirp_select_poll(slirp, &slirp->rfds, &slirp->wfds, &slirp->xfds, timeMS, r >= 0); }
// // __syscall (int number, ...) // static VMIOS_INTERCEPT_FN(syscallCB) { Uns32 code; getArg(processor, object, 0, &code); vmiMessage("F", CPU_PREFIX "_UNSUPPORTED", "__syscall with code %d", code); }
void netRxPacket(void *opaque, const void *buf, Uns32 len) { vmiosObjectP object = opaque; if(object->count >= 32) { vmiMessage("F", PREFIX, "Too many packets queued in one poll period. Dropped"); return; } if(len >= MAX_LENGTH) { vmiMessage("E", PREFIX, "rxBuffer is too small for packet (needed:%d, space:%d). Dropped", len, MAX_LENGTH ); return; } Uns32 packetAddr =object->packets + (sizeof(packet) * object->count); vmirtWriteNByteDomain(object->domain, packetAddr, &len, 4, NULL, 0); vmirtWriteNByteDomain(object->domain, packetAddr+4, buf, len, NULL, 0); object->count++; }
// // Split function result into result (0/-1) and errno (-result) // static void setErrnoAndResult( vmiProcessorP processor, vmiosObjectP object, Int32 result, const char *context ) { if(!object->impurePtrDomain) { vmiMessage("P", "OR1K_ICF_NEWLIB", "Interception of '%s' failed - %s not found " "(application does not appear to be compiled with newlib " "or has no symbols)", context, ERRNO_REF ); vmirtFinish(-1); } else if(result<0) { memDomainP domain = object->impurePtrDomain; memEndian endian = vmirtGetProcessorDataEndian(processor); Int32 errnoValue = -result; Uns32 impurePtrAddr; result = -1; // swap errno endianness if required if(endian != ENDIAN_NATIVE) { errnoValue = swap4(errnoValue); } // read __impure_ptr value vmirtReadNByteDomain( domain, object->impurePtrAddr, &impurePtrAddr, sizeof(impurePtrAddr), 0, False ); // swap errno address endianness if required if(endian != ENDIAN_NATIVE) { impurePtrAddr = swap4(impurePtrAddr); } // write back errno vmirtWriteNByteDomain( domain, impurePtrAddr+OR1K_ERRNO_OFFSET, &errnoValue, sizeof(errnoValue), 0, True ); } vmiosRegWrite(processor, object->result, &result); }
// Constructor // static VMIOS_CONSTRUCTOR_FN(constructor) { if(DIAG_LOW) vmiMessage("I", PREFIX, "Starting SLIRP"); // What am I ? const char *procType = vmirtProcessorType(processor); if (strcmp(procType, "pse") != 0) { vmiMessage("F", PREFIX, "Processor must be a PSE"); } memEndian endian = vmirtGetProcessorDataEndian(processor); if(endian != ENDIAN_NATIVE) { vmiMessage("F", PREFIX, "Host processor must have same endianity as a PSE"); } // return register (standard ABI) object->result = vmiosGetRegDesc(processor, "eax"); // stack pointer (standard ABI) object->sp = vmiosGetRegDesc(processor, "esp"); object->count = 0; }
// // Intercept times // static VMIOS_INTERCEPT_FN(timesInt) { Uns32 bufAddr; Int32 result = 0; // obtain function arguments getArg(processor, object, 0, &bufAddr); // ioctl isn't implemented vmiMessage("W", "OR1K_UNS_NEWLIB1", "times(0x%x) unsupported\n", bufAddr); // write back results setErrnoAndResult(processor, object, result, context); }
static VMIOS_INTERCEPT_FN(netTxPacket) { Uns32 addr, bytes; getArg(processor, object, 0, &addr); getArg(processor, object, 1, &bytes); // copy data from PSE to host memory space. Uns8 packet[bytes]; vmirtReadNByteDomain(object->domain, addr, packet, bytes, NULL, False); if(DIAG_HIGH) vmiMessage("I", PREFIX, "netTxPacket bytes:%d", bytes); // send to slirp slirp_input(object->slirp, packet, bytes); }
// // Read a function argument using the standard ABI // static void getArg( vmiProcessorP processor, vmiosObjectP object, Uns32 index, void *result ) { if(index>=REG_ARG_NUM) { vmiMessage("P", CPU_PREFIX"_ANS", "No more than %u function arguments supported", REG_ARG_NUM ); vmirtFinish(-1); } else { vmiRegInfoCP regCP = getArgCP(processor, object, index); vmiosRegRead(processor, regCP, result); } }
// // Return the next available file descriptor // static Int32 newFileDescriptor(vmiosObjectP object, const char *context) { Int32 i; // find and return the first unused file descriptor for(i=0; i<FILE_DES_NUM; i++) { if(object->fileDescriptors[i]==-1) { return i; } } vmiMessage("P", "OR1K_TMOF_NEWLIB", "Too many open files in %s - semihosting supports up to %u", context, FILE_DES_NUM ); return -1; }
// // Intercept ioctl // static VMIOS_INTERCEPT_FN(ioctlInt) { Int32 d; Int32 request; Int32 result = 0; // obtain function arguments getArg(processor, object, 0, &d); getArg(processor, object, 1, &request); // ioctl isn't implemented vmiMessage("W", "OR1K_UNS_NEWLIB2", "ioctl(%d, %d, ...) unsupported\n", d, request ); // write back results setErrnoAndResult(processor, object, result, context); }
// // Get the Constant pointer for the register // static vmiRegInfoCP getArgCP( vmiProcessorP processor, vmiosObjectP object, Uns32 index ) { vmiRegInfoCP regCP = 0; if(index>=REG_ARG_NUM) { vmiMessage("P", CPU_PREFIX"_ANS", "No more than %u function arguments supported", REG_ARG_NUM ); vmirtFinish(-1); } else { regCP = object->args[index]; } return regCP; }
// // Read a function argument using the standard ABI // static void getArg( vmiProcessorP processor, vmiosObjectP object, Uns32 index, void *result ) { if(index>=REG_ARG_NUM) { vmiMessage("P", "OR1K_ANS_NEWLIB", "No more than %u function arguments supported", REG_ARG_NUM ); vmirtFinish(-1); } else { vmiosRegRead(processor, object->args[index], result); } }
// // Destructor // static VMIOS_DESTRUCTOR_FN(destructor) { if(DIAG_LOW) vmiMessage("I" ,PREFIX, "Shutting down SLIRP"); }
static void redirPort(Slirp *slirp, const char *p, const char *procName) { do { Bool udp = False; char buf[256], *r; struct in_addr host_addr; struct in_addr guest_addr; int host_port, guest_port; memset(&host_addr, 0, sizeof(host_addr)); host_addr.s_addr = INADDR_ANY; if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) redirStringError("expected tcp: or udp:"); if (!strcmp(buf, "tcp")) { udp = 0; } else if (!strcmp(buf, "udp")) { udp = 1; } else { vmiMessage("F", PREFIX, "expected tcp: or udp:"); } if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) redirStringError("expected host port number"); host_port = strtol(buf, &r, 0); if (r == buf) redirStringError("expected host port number"); if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) redirStringError("expected guest ip address"); if (buf[0] == '\0') { strcpy(buf, "10.0.2.15"); } else { if (!inet_aton(buf, &guest_addr)) redirStringError("expected guest ip address"); } guest_port = strtol(p, &r, 0); if (r == p) redirStringError("expected guest port number"); Uns32 actualHostPort = 0; int res = slirp_add_hostfwd( slirp, udp, host_addr, host_port, guest_addr, guest_port, &actualHostPort ); if (res >= 0) { vmiMessage("I", PREFIX, "%s Listening on host %s port:%d. Redirecting to guest port:%d", procName, udp ? "udp" : "tcp", // host_port, actualHostPort, guest_port ); } else { vmiMessage("W", PREFIX, "Failed to set up redirection on port %d", guest_port); } p = r; if(*p != ',') break; p++; } while (1); }
static void redirStringError(const char *what) { vmiMessage("F", PREFIX, "Error parsing redirection : %s", what); }
// // Decoder function for a given address // void microblazeDecode( microblazeP microblaze, microblazeAddr thisPC, microblazeInstructionInfoP info ) { // // Initialize the 32 bit decoder table // static vmidDecodeTableP decodeTable32; if(!decodeTable32) { decodeTable32 = microblazeCreateDecodeTable32(); } vmiProcessorP processor = (vmiProcessorP)microblaze; // // Initialize the following info fields before lookup // info->type = MICROBLAZE_IT_INSTR32; info->thisPC = thisPC; info->arch = microblaze->configInfo.arch; Uns64 instruction = 0; info->instrsize = 0; // // Attempt to match a 32 bit instruction // if (info->type == MICROBLAZE_IT_INSTR32) { Uns64 instr4 = vmicxtFetch4Byte(processor, thisPC); info->type = MICROBLAZE_IT_LAST; info->type = vmidDecode(decodeTable32, instr4); info->nextPC = info->thisPC + 4; instruction = instr4; info->instrsize = 4; info->instruction = instr4; } // // Fatal if there was a match failure // if (info->type == MICROBLAZE_IT_LAST && MICROBLAZE_DISASSEMBLE(microblaze)) { vmiMessage("F", "DECODE_FAIL", "Address=0x" FMT_640Nx " Instruction = 0x" FMT_640Nx, (Uns64)thisPC, instruction); } microblazeGenInstructionInfo(info, instruction); // // If this is a decode of an IMM instruction, we decode the next instruction // if (info->type == MICROBLAZE_IT_IMM_TYPEI1) { Uns64 instr4 = vmicxtFetch4Byte(processor, info->nextPC); info->type = MICROBLAZE_IT_LAST; info->type = vmidDecode(decodeTable32, instr4); info->thisPC = info->nextPC; info->nextPC = info->thisPC + 4; instruction = instr4; info->instrsize = 8; info->instruction = instr4; // // Fatal if there was a match failure // if (info->type == MICROBLAZE_IT_LAST && MICROBLAZE_DISASSEMBLE(microblaze)) { vmiMessage("F", "DECODE_FAIL", "Address=0x" FMT_640Nx " Instruction = 0x" FMT_640Nx, (Uns64)info->nextPC, instruction); } // // get the fields for the TYPEB instruction // microblazeGenInstructionInfo(info, instruction); } else { // Indicate that the simmhi is unset info->simmhi = 0x0000ffff; } }