// 物理的にパケットを送信する void pro100_send_packet_to_line(PRO100_CTX *ctx, void *buf, UINT size) { volatile PRO100_OP_BLOCK *b; PRO100_OP_TRANSMIT *t; phys_t ptr; // 引数チェック if (ctx == NULL || buf == NULL || size == 0) { return; } // メモリ確保 b = pro100_alloc_page(&ptr); t = (PRO100_OP_TRANSMIT *)b; t->op_block.op = PRO100_CU_OP_TRANSMIT; t->op_block.transmit_flexible_mode = 0; t->op_block.transmit_raw_packet = 0; t->op_block.transmit_cid = 31; t->op_block.i = false; t->op_block.s = false; t->op_block.el = true; t->op_block.link_address = 0; t->tbd_array_address = 0xffffffff; t->data_bytes = size; t->threshold = 1; SeCopy(((UCHAR *)b) + sizeof(PRO100_OP_TRANSMIT) + (ctx->use_standard_txcb ? 0 : sizeof(PRO100_TBD) * 2), buf, size); if (false) { char tmp[8000]; SeBinToStrEx(tmp, sizeof(tmp), (void *)b, size + sizeof(PRO100_OP_TRANSMIT)); printf("%s\n\n", tmp); } pro100_init_cu_base_addr(ctx); pro100_wait_cu_ru_accepable(ctx); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ptr, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_START, PRO100_RU_CMD_NOOP), 1); pro100_flush(ctx); //printf("1\n"); while (b->c == false); //printf("2\n"); pro100_free_page((void *)b, ptr); }
// バイナリデータのデバッグ出力 void SeDebugBin(void *data, UINT size) { char *tmp; UINT tmp_size; // 引数チェック if (data == NULL) { return; } tmp_size = (size + 2) * 3; tmp = SeMalloc(tmp_size); SeBinToStrEx(tmp, tmp_size, data, size); SeDebug("%s", tmp); SeFree(tmp); }
// ゲスト OS が開始したオペレーションを処理する void pro100_proc_guest_op(PRO100_CTX *ctx) { phys_t ptr; // 引数チェック if (ctx == NULL) { return; } if (ctx->guest_cu_started == false || ctx->guest_cu_current_pointer == 0) { return; } ptr = ctx->guest_cu_current_pointer; // 終端まで読み取る while (true) { PRO100_OP_BLOCK_MAX b; if (ctx->guest_cu_suspended) { // サスペンド中の場合、前回の最後のオペレーションの S ビットがクリア // されたかどうか検査する pro100_mem_read(&b, ptr, sizeof(b)); if (b.op_block.s) { // サスペンド継続中 break; } ptr = ctx->guest_cu_next_pointer; ctx->guest_cu_suspended = false; } pro100_mem_read(&b, ptr, sizeof(b)); if (b.op_block.op == PRO100_CU_OP_TRANSMIT) { // 送信処理 PRO100_OP_TRANSMIT *t = (PRO100_OP_TRANSMIT *)&b; if (false) { printf("flexible_mode=%u, raw_packet=%u, cid=%u, array=0x%x, thres=%u, tcount=%u, size=%u\n", t->op_block.transmit_flexible_mode, t->op_block.transmit_raw_packet, t->op_block.transmit_cid, t->tbd_array_address, t->threshold, t->tbd_count, t->data_bytes); } //printf("SEND\n"); if (false) { char tmp[4096]; SeBinToStrEx(tmp, sizeof(tmp), &b, 24); printf("%s\n", tmp); } if (true) { UCHAR buf[PRO100_MAX_PACKET_SIZE]; UINT packet_size = pro100_read_send_packet(ctx, ptr, buf); #ifdef PRO100_PASS_MODE pro100_write_recv_packet(ctx, buf, packet_size); #else // PRO100_PASS_MODE if (ctx->CallbackRecvVirtNic != NULL) { void *packet_data[1]; UINT packet_sizes[1]; packet_data[0] = buf; packet_sizes[0] = packet_size; ctx->CallbackRecvVirtNic(ctx, 1, packet_data, packet_sizes, ctx->CallbackRecvVirtNicParam); } #endif // PRO100_PASS_MODE } b.op_block.ok = b.op_block.c = true; b.op_block.transmit_overrun = false; pro100_mem_write(ptr, &b, sizeof(PRO100_OP_BLOCK) + sizeof(PRO100_OP_TRANSMIT)); if (b.op_block.i) { pro100_generate_int(ctx); } } else { // 送信以外の処理 UINT size = pro100_get_op_size(b.op_block.op, &b); //printf("0x%x: OP: %u Size=%u\n", (UINT)ptr, b.op_block.op, size); switch (b.op_block.op) { case PRO100_CU_OP_IA_SETUP: // IA Setup SeCopy(ctx->mac_address, ((UCHAR *)&b) + sizeof(PRO100_OP_BLOCK), 6); pro100_init_vpn_client(ctx); break; case PRO100_CU_OP_CONFIG: // Configure ctx->use_standard_txcb = ((((UCHAR *)&b)[sizeof(PRO100_OP_BLOCK) + 6] & 0x10) ? true : false); break; } pro100_exec_cu_op(ctx, &b, size); pro100_mem_write(ptr, &b, size); } if (b.op_block.el) { // 終了フラグ ctx->guest_cu_started = false; ctx->guest_cu_current_pointer = 0; ctx->guest_cu_suspended = false; //printf("EL\n"); pro100_generate_int(ctx); break; } if (b.op_block.s) { // サスペンドフラグ ctx->guest_cu_suspended = true; ctx->guest_cu_next_pointer = b.op_block.link_address; //printf("SUSPEND\n"); pro100_generate_int(ctx); break; } ptr = b.op_block.link_address; } if (ctx->guest_cu_started) { ctx->guest_cu_current_pointer = ptr; } }
// CU にオペレーションを実行させる void pro100_exec_cu_op(PRO100_CTX *ctx, PRO100_OP_BLOCK_MAX *op, UINT size) { volatile PRO100_OP_BLOCK *b; PRO100_OP_BLOCK *b2; phys_t ptr; bool src_el, src_s, src_i; UINT src_link_addr; bool timeouted; UINT64 start_tick; // 引数チェック if (ctx == NULL || op == NULL) { return; } // メモリ確保 b = pro100_alloc_page(&ptr); // 一時領域にコピー SeCopy((void *)b, op, size); // バックアップ src_el = b->el; src_s = b->s; src_i = b->i; src_link_addr = b->link_address; // フラグセット b->el = true; b->s = false; //b->ok = b->c = false; b->link_address = ptr; //b->i = false; pro100_init_cu_base_addr(ctx); pro100_wait_cu_ru_accepable(ctx); if (false) { char tmp[4096]; SeBinToStrEx(tmp, sizeof(tmp), (void *)b, size); printf("%s\n", tmp); } pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ptr, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_START, PRO100_RU_CMD_NOOP), 1); pro100_flush(ctx); // NIC がコマンドを完了するまで待機 //printf("["); start_tick = SeTick64(); timeouted = true; while ((start_tick + 1000ULL) >= SeTick64()) { if (b->c) { timeouted = false; break; } } //printf("%u] ", b->c); //b->c = true; if (false) { UINT t = pro100_read(ctx, PRO100_CSR_OFFSET_SCB_STATUS_WORD_0, 1); PRO100_SCB_STATUS_WORD_BIT *b = (PRO100_SCB_STATUS_WORD_BIT *)(void *)&t; printf("STATUS CU=%u, RU=%u\n", b->cu_status, b->ru_status); } // 結果を書き戻す SeCopy(op, (void *)b, size); b2 = (PRO100_OP_BLOCK *)op; // バックアップを復元 b2->el = src_el; b2->s = src_s; b2->i = src_i; b2->link_address = src_link_addr; // メモリ解放 pro100_free_page((void *)b, ptr); if (timeouted && src_i) { //pro100_generate_int(ctx); } }