// RU のベースアドレスの初期化を実行 void pro100_init_ru_base_addr(PRO100_CTX *ctx) { // 引数チェック if (ctx == NULL) { return; } if (ctx->ru_base_inited) { return; } ctx->ru_base_inited = true; pro100_wait_cu_ru_accepable(ctx); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, 0, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_NOOP, PRO100_RU_CMD_LOAD_RU_BASE), 1); pro100_wait_cu_ru_accepable(ctx); }
// 物理的にパケットを送信する 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); }
// 書き込みフック bool pro100_hook_write(PRO100_CTX *ctx, UINT offset, UINT data, UINT size) { // 引数チェック if (ctx == NULL) { return false; } switch (offset) { case PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0: // RU Command, CU Command if (size == 1) { UCHAR b = (UCHAR)data; UINT ru = PRO100_GET_RU_COMMAND(b); UINT cu = PRO100_GET_CU_COMMAND(b); char *s1 = NULL; char *s2 = NULL; s1 = pro100_get_ru_command_string(ru); s2 = pro100_get_cu_command_string(cu); if (s1 != NULL || s2 != NULL) { //printf("[%s, %s] ", s1, s2); } switch (cu) { case PRO100_CU_CMD_NOOP: break; case PRO100_CU_CMD_START: //printf("GUEST PRO100_CU_CMD_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ctx->guest_cu_started = true; ctx->guest_cu_suspended = false; ctx->guest_cu_start_pointer = (phys_t)ctx->guest_last_general_pointer; ctx->guest_cu_current_pointer = ctx->guest_cu_start_pointer; pro100_proc_guest_op(ctx); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_RESUME: //printf("GUEST PRO100_CU_CMD_RESUME\n"); pro100_proc_guest_op(ctx); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_LOAD_CU_BASE: //printf("GUEST PRO100_CU_CMD_LOAD_CU_BASE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; ctx->cu_base_inited = false; break; case PRO100_CU_CMD_LOAD_DUMP_ADDR: //printf("GUEST PRO100_CU_CMD_LOAD_DUMP_ADDR: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; //pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); break; case PRO100_CU_CMD_DUMP_STAT: //printf("GUEST PRO100_CU_CMD_DUMP_STAT\n"); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_DUMP_AND_RESET_STAT: //printf("GUEST PRO100_CU_CMD_DUMP_AND_RESET_STAT\n"); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_HPQ_START: //printf("GUEST PRO100_CU_CMD_HPQ_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_CU_STAT_RESUME: //printf("GUEST PRO100_CU_CMD_CU_STAT_RESUME\n"); //pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); //cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_HPQ_RESUME: //printf("GUEST PRO100_CU_CMD_HPQ_RESUME\n"); cu = PRO100_CU_CMD_NOOP; break; default: printf("!!!! GUEST SEND UNKNOWN CU CMD: %u\n", cu); break; } switch (ru) { case PRO100_RU_CMD_NOOP: break; case PRO100_RU_CMD_START: //printf("GUEST PRO100_RU_CMD_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; // ゲスト OS が指定してきた受信バッファのポインタを記憶する ctx->guest_rfd_current = ctx->guest_rfd_first = (phys_t)ctx->guest_last_general_pointer; pro100_poll_ru(ctx); break; case PRO100_RU_CMD_RESUME: //printf("GUEST PRO100_RU_CMD_RESUME\n"); ru = PRO100_CU_CMD_NOOP; ctx->guest_ru_suspended = false; pro100_poll_ru(ctx); break; case PRO100_RU_CMD_LOAD_HEADER_DATA_SIZE: //printf("GUEST PRO100_RU_CMD_LOAD_HEADER_DATA_SIZE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; break; case PRO100_RU_CMD_LOAD_RU_BASE: //printf("GUEST PRO100_RU_CMD_LOAD_RU_BASE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; ctx->ru_base_inited = false; break; default: printf("!!!! GUEST SEND UNKNOWN RU CMD: %u\n", cu); break; } ru = 0; b = PRO100_MAKE_CU_RU_COMMAND(cu, ru); if ((cu != 0 || ru != 0) && (cu == 0 || ru == 0)) { //printf("<P"); pro100_wait_cu_ru_accepable(ctx); //printf(">"); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, b, 1); //printf("<Y"); pro100_wait_cu_ru_accepable(ctx); //printf(">"); } return true; } break; case PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1: // 割り込み制御ビット if (size == 1) { ctx->int_mask_guest_set = data; if (true) { //PRO100_INT_BIT *ib = (PRO100_INT_BIT *)&ctx->int_mask_guest_set; //printf("int mask: M=%u 0x%x\n", (UINT)ib->mask_all, (UINT)ctx->int_mask_guest_set); /* ib->mask_all = true; ib->fcp = ib->er = ib->rnr = ib->cna = ib->fr = ib->cx = 1; */ //pro100_beep((ib->mask_all == 0 ? 880 : 440), 200); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1, ctx->int_mask_guest_set, 4); return true; } } break; case PRO100_CSR_OFFSET_SCB_GENERAL_POINTER: // 汎用ポインタ if (size == 4) { ctx->guest_last_general_pointer = data; //printf("GUEST WRITES POINTER: 0x%x\n", data); } return true; case PRO100_CSR_OFFSET_SCB_STATUS_WORD_1: // STAT/ACK /*if (size == 1) { printf("<ACK>"); if (data != 0) { pro100_write(ctx, PRO100_CSR_OFFSET_SCB_STATUS_WORD_1, 0xff, 1); } return true; }*/ pro100_poll_ru(ctx); break; case PRO100_CSR_OFFSET_SCB_PORT: // ポート break; case PRO100_CSR_OFFSET_SCB_MDI: // MDI break; default: //printf("*** ACCESS TO 0x%x size=%u data=0x%x\n", offset, size, data); break; } return false; }
// 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); } }
// RU をポーリングする void pro100_poll_ru(PRO100_CTX *ctx) { bool b = false; // 引数チェック if (ctx == NULL) { return; } LABEL_LOOP: pro100_init_ru_base_addr(ctx); if (ctx->host_ru_started == false) { // RU を開始する ctx->host_ru_started = true; pro100_wait_cu_ru_accepable(ctx); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->first_recv->rfd_ptr, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, PRO100_MAKE_CU_RU_COMMAND(PRO100_CU_CMD_NOOP, PRO100_RU_CMD_START), 1); pro100_flush(ctx); pro100_wait_cu_ru_accepable(ctx); } // 新しいパケットが到着しているかどうか確認する while (true) { if (ctx->current_recv->rfd->c) { UCHAR *data; UINT size; // パケットが到着した data = &ctx->current_recv->rfd->data[0]; size = ctx->current_recv->rfd->recved_bytes; if (size >= 1 && size <= PRO100_MAX_PACKET_SIZE) { // パケット受信完了 #ifdef PRO100_PASS_MODE pro100_write_recv_packet(ctx, data, size); #else // PRO100_PASS_MODE if (ctx->CallbackRecvPhyNic != NULL) { void *packet_data[1]; UINT packet_size[1]; packet_data[0] = data; packet_size[0] = size; ctx->CallbackRecvPhyNic(ctx, 1, packet_data, packet_size, ctx->CallbackRecvPhyNicParam); } #endif // PRO100_PASS_MODE } ctx->current_recv = ctx->current_recv->next_recv; if (ctx->current_recv == NULL) { // 最後の受信バッファまで受信が完了したのでバッファをリセットする pro100_init_recv_buffer(ctx); ctx->host_ru_started = false; b = true; break; } } else { break; } } if (b) { b = false; goto LABEL_LOOP; } }
// 書き込みフック bool pro100_hook_write(PRO100_CTX *ctx, UINT offset, UINT data, UINT size) { // 引数チェック if (ctx == NULL) { return false; } switch (offset) { case PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0: // RU Command, CU Command if (size != 1) { debugprint("pro100_hook_write: PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0: BAD SIZE: %u\n", size); } if (size == 1) { UCHAR b = (UCHAR)data; UINT ru = PRO100_GET_RU_COMMAND(b); UINT cu = PRO100_GET_CU_COMMAND(b); char *s1 = NULL; char *s2 = NULL; s1 = pro100_get_ru_command_string(ru); s2 = pro100_get_cu_command_string(cu); if (s1 != NULL || s2 != NULL) { //debugprint("[%s, %s] ", s1, s2); } switch (cu) { case PRO100_CU_CMD_NOOP: break; case PRO100_CU_CMD_START: //debugprint("GUEST PRO100_CU_CMD_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ctx->guest_cu_started = true; ctx->guest_cu_suspended = false; ctx->guest_cu_start_pointer = (phys_t)ctx->guest_last_general_pointer; ctx->guest_cu_current_pointer = ctx->guest_cu_start_pointer; pro100_proc_guest_op(ctx); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_RESUME: //debugprint("GUEST PRO100_CU_CMD_RESUME\n"); pro100_proc_guest_op(ctx); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_LOAD_CU_BASE: //debugprint("GUEST PRO100_CU_CMD_LOAD_CU_BASE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; ctx->cu_base_inited = false; break; case PRO100_CU_CMD_LOAD_DUMP_ADDR: debugprint("GUEST PRO100_CU_CMD_LOAD_DUMP_ADDR: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; //pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); ctx->guest_last_counter_pointer = ctx->guest_last_general_pointer; break; case PRO100_CU_CMD_DUMP_STAT: case PRO100_CU_CMD_DUMP_AND_RESET_STAT: debugprint(cu == PRO100_CU_CMD_DUMP_STAT ? "GUEST PRO100_CU_CMD_DUMP_STAT\n" : "GUEST PRO100_CU_CMD_DUMP_AND_RESET_STAT\n"); if (ctx->guest_last_counter_pointer != 0) { UINT dummy_data[21]; // ゲスト OS がカウンタデータのダンプを要求しているのでウソのデータを返す // (これをしないと Windows 版ドライバの一部で 2 秒間のビジーループによる待ちが発生してしまう) memset(dummy_data, 0, sizeof(dummy_data)); dummy_data[16] = dummy_data[19] = dummy_data[20] = (cu == PRO100_CU_CMD_DUMP_STAT ? 0xa005 : 0xa007); pro100_mem_write((phys_t)ctx->guest_last_counter_pointer, dummy_data, sizeof(dummy_data)); } else { debugprint("error: ctx->guest_last_counter_pointer == 0\n"); } cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_HPQ_START: //debugprint("GUEST PRO100_CU_CMD_HPQ_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_CU_STAT_RESUME: //debugprint("GUEST PRO100_CU_CMD_CU_STAT_RESUME\n"); //pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); //cu = PRO100_CU_CMD_NOOP; break; case PRO100_CU_CMD_HPQ_RESUME: //debugprint("GUEST PRO100_CU_CMD_HPQ_RESUME\n"); cu = PRO100_CU_CMD_NOOP; break; default: printf("!!!! GUEST SEND UNKNOWN CU CMD: %u\n", cu); break; } switch (ru) { case PRO100_RU_CMD_NOOP: break; case PRO100_RU_CMD_START: //debugprint("GUEST PRO100_RU_CMD_START: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; // ゲスト OS が指定してきた受信バッファのポインタを記憶する ctx->guest_rfd_current = ctx->guest_rfd_first = (phys_t)ctx->guest_last_general_pointer; pro100_poll_ru(ctx); break; case PRO100_RU_CMD_RESUME: //debugprint("GUEST PRO100_RU_CMD_RESUME\n"); ru = PRO100_CU_CMD_NOOP; ctx->guest_ru_suspended = false; pro100_poll_ru(ctx); break; case PRO100_RU_CMD_LOAD_HEADER_DATA_SIZE: //debugprint("GUEST PRO100_RU_CMD_LOAD_HEADER_DATA_SIZE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; break; case PRO100_RU_CMD_LOAD_RU_BASE: //debugprint("GUEST PRO100_RU_CMD_LOAD_RU_BASE: 0x%x\n", (UINT)ctx->guest_last_general_pointer); ru = PRO100_CU_CMD_NOOP; ctx->ru_base_inited = false; break; default: printf("!!!! GUEST SEND UNKNOWN RU CMD: %u\n", ru); break; } ru = 0; b = PRO100_MAKE_CU_RU_COMMAND(cu, ru); if ((cu != 0 || ru != 0) && (cu == 0 || ru == 0)) { debugprint("<P"); pro100_wait_cu_ru_accepable(ctx); debugprint(">"); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_GENERAL_POINTER, (UINT)ctx->guest_last_general_pointer, 4); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_0, b, 1); debugprint("<Y"); pro100_wait_cu_ru_accepable(ctx); debugprint(">"); } return true; } break; case PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1: // 割り込み制御ビット if (size != 1) { debugprint("pro100_hook_write: PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1: BAD SIZE: %u\n", size); } if (size == 1) { ctx->int_mask_guest_set = data; if (true) { //PRO100_INT_BIT *ib = (PRO100_INT_BIT *)&ctx->int_mask_guest_set; //debugprint("int mask: M=%u 0x%x\n", (UINT)ib->mask_all, (UINT)ctx->int_mask_guest_set); /* ib->mask_all = true; ib->fcp = ib->er = ib->rnr = ib->cna = ib->fr = ib->cx = 1; */ //pro100_beep((ib->mask_all == 0 ? 880 : 440), 200); pro100_write(ctx, PRO100_CSR_OFFSET_SCB_COMMAND_WORD_1, ctx->int_mask_guest_set, 4); return true; } } break; case PRO100_CSR_OFFSET_SCB_GENERAL_POINTER: // 汎用ポインタ if (size != 4) { debugprint("pro100_hook_write: PRO100_CSR_OFFSET_SCB_GENERAL_POINTER: BAD SIZE: %u\n", size); } if (size == 4) { ctx->guest_last_general_pointer = data; //debugprint("GUEST WRITES POINTER: 0x%x\n", data); } return true; case PRO100_CSR_OFFSET_SCB_STATUS_WORD_1: // STAT/ACK /*if (size == 1) { debugprint("<ACK>"); if (data != 0) { pro100_write(ctx, PRO100_CSR_OFFSET_SCB_STATUS_WORD_1, 0xff, 1); } return true; }*/ pro100_poll_ru(ctx); break; case PRO100_CSR_OFFSET_SCB_PORT: // ポート break; case PRO100_CSR_OFFSET_SCB_MDI: // MDI break; default: if (offset == 0 && size == 2) { UCHAR buf[4]; *((UINT *)buf) = data; pro100_hook_write(ctx, 1, buf[1], 1); return true; } else { if (offset < 0x10) { printf("*** WRITE ACCESS TO 0x%x size=%u data=0x%x\n", offset, size, data); } } break; } return false; }