--- nono/vm/rtl8019as.cpp 2026/04/29 17:05:29 1.1.1.3 +++ nono/vm/rtl8019as.cpp 2026/04/29 17:06:01 1.1.1.8 @@ -39,7 +39,9 @@ // Page3: E1 30 00 00 90 00 10 FF 00 FE FF FD FF FE FF FF #include "rtl8019as.h" +#include "event.h" #include "interrupt.h" +#include "monitor.h" #include "scheduler.h" // コンストラクタ @@ -49,13 +51,13 @@ RTL8019ASDevice::RTL8019ASDevice(uint n, SetName(string_format("RTL8019AS#%u", n)); ClearAlias(); AddAlias(string_format("RTL8019AS%u", n)); - AddAlias(string_format("Eth%u", n)); + AddAlias(string_format("Net%u", n)); intr_vector = vector_; - monitor.func = ToMonitorCallback(&RTL8019ASDevice::MonitorUpdate); - monitor.SetSize(71, 19); - monitor.Regist(ID_MONITOR_RTL8019AS(n)); + monitor = gMonitorManager->Regist(ID_MONITOR_RTL8019AS(n), this); + monitor->SetCallback(&RTL8019ASDevice::MonitorScreen); + monitor->SetSize(71, 19); } // デストラクタ @@ -67,24 +69,19 @@ RTL8019ASDevice::~RTL8019ASDevice() bool RTL8019ASDevice::Init() { - if (inherited::Init() == false) { - return false; - } - uint n = GetId() - OBJ_ETHERNET0; + hostnet->SetPortName(string_format("Nereid#%u", n)); + // MAC アドレスを取得 - macaddr_t macaddr; + MacAddr macaddr; if (inherited::GetConfigMacAddr(n, &macaddr, false) == false) { // エラーメッセージ表示済み return false; } // PROM 領域 (実質16バイト) を作成 memset(&prom[0], 0xff, prom.size()); - uint8 *d = &prom[0]; - for (auto m : macaddr) { - *d++ = m; - } + macaddr.ExportTo(&prom[0]); prom[0xe] = 'W'; prom[0xf] = 'W'; @@ -94,19 +91,20 @@ RTL8019ASDevice::Init() scheduler->ConnectMessage(MessageID::HOSTNET_RX(n), this, ToMessageCallback(&RTL8019ASDevice::RxMessage)); - tx_event.func = ToEventCallback(&RTL8019ASDevice::TXEvent); - tx_event.SetName(string_format("RTL8019AS%u TX", n)); - rx_event.func = ToEventCallback(&RTL8019ASDevice::RXEvent); - rx_event.SetName(string_format("RTL8019AS%u RX", n)); - scheduler->RegistEvent(tx_event); - scheduler->RegistEvent(rx_event); - - txled_event.func = ToEventCallback(&RTL8019ASDevice::TXLedEvent); - txled_event.SetName(string_format("RTL8019AS%u TX LED", n)); - rxled_event.func = ToEventCallback(&RTL8019ASDevice::RXLedEvent); - rxled_event.SetName(string_format("RTL8019AS%u RX LED", n)); - scheduler->RegistEvent(txled_event); - scheduler->RegistEvent(rxled_event); + auto evman = GetEventManager(); + tx_event = evman->Regist(this, + ToEventCallback(&RTL8019ASDevice::TXEvent), + string_format("RTL8019AS%u TX", n)); + rx_event = evman->Regist(this, + ToEventCallback(&RTL8019ASDevice::RXEvent), + string_format("RTL8019AS%u RX", n)); + + txled_event = evman->Regist(this, + ToEventCallback(&RTL8019ASDevice::TXLedEvent), + string_format("RTL8019AS%u TX LED", n)); + rxled_event = evman->Regist(this, + ToEventCallback(&RTL8019ASDevice::RXLedEvent), + string_format("RTL8019AS%u RX LED", n)); return true; } @@ -311,7 +309,7 @@ RTL8019ASDevice::Peek1(uint32 addr) } void -RTL8019ASDevice::MonitorUpdate(Monitor *, TextScreen& screen) +RTL8019ASDevice::MonitorScreen(Monitor *, TextScreen& screen) { uint32 val; const int x = 6; @@ -405,9 +403,8 @@ RTL8019ASDevice::MonitorUpdate(Monitor * // マルチキャストフィルタは MAR0 が右側 (リトルエンディアンぽい感じ)。 // MAR7-0: $00000000'00000000 - uint32 marH = (mar[7] << 24) | (mar[6] << 16) | (mar[5] << 8) | mar[4]; - uint32 marL = (mar[3] << 24) | (mar[2] << 16) | (mar[1] << 8) | mar[0]; - screen.Print(x + 23, y, "MAR7-0: $%08x'%08x", marH, marL); + screen.Print(x + 23, y, "MAR7-0: $%08x'%08x", + (uint32)(mar >> 32), (uint32)mar); y++; y++; @@ -515,9 +512,12 @@ RTL8019ASDevice::MonitorUpdate(Monitor * // y++; screen.Puts(0, y, "LED:"); - screen.Puts(x, y, TA::ReverseOrange, "LED1(LINK)"); - screen.Puts(x + 12, y, tx_led ? TA::ReverseRed : TA::Off, "LED2(TX)"); - screen.Puts(x + 22, y, rx_led ? TA::ReverseGreen : TA::Off, "LED3(RX)"); + screen.Puts(x, y, TA::ReverseOrange, "LED1"); + screen.Puts(x + 4, y, "(LINK)"); + screen.Puts(x + 11, y, tx_led ? TA::ReverseRed : TA::Off, "LED2"); + screen.Puts(x + 15, y, "(TX)"); + screen.Puts(x + 20, y, rx_led ? TA::ReverseGreen : TA::Off, "LED3"); + screen.Puts(x + 24, y, "(RX)"); // 右カラム y = 0; @@ -546,7 +546,7 @@ RTL8019ASDevice::MonitorUpdate(Monitor * screen.Print(x2, y++, "CNTR2 = $%02x", PeekCNTR(2)); } -// レジスタをビットごとに表示する。MonitorUpdate の下請け。 +// レジスタをビットごとに表示する。MonitorScreen の下請け。 // "-" で始まっていたら Disable 色にし、次の文字から表示。 void RTL8019ASDevice::MonitorReg(TextScreen& screen, @@ -556,7 +556,7 @@ RTL8019ASDevice::MonitorReg(TextScreen& if (names[i][0] == '-') { screen.Puts(x + i * 6, y, TA::Disable, names[i] + 1); } else { - bool b = reg & (1 << (7 - i)); + bool b = reg & (1U << (7 - i)); screen.Puts(x + i * 6, y, TA::OnOff(b), names[i]); } } @@ -1196,9 +1196,6 @@ RTL8019ASDevice::WriteRCR(uint32 data) accept_bcast = (data & RTL8019::RCR_AB); accept_short = (data & RTL8019::RCR_AR); accept_error = (data & RTL8019::RCR_SEP); - - // プロミスキャスの設定はここで行う? - hostnet->SetPromisc(promisc_mode); } // TCR レジスタ書き込み @@ -1279,15 +1276,14 @@ RTL8019ASDevice::WriteCURR(uint32 data) void RTL8019ASDevice::WriteMAR(uint n, uint32 data) { - mar[n] = data; + mar &= ~(0xffULL << (n * 8)); + mar |= (uint64)data << (n * 8); if (__predict_false(loglevel >= 3)) { putlogn("MAR%u <- $%02x", n, data); } else { if (__predict_false(n == 7)) { - putlog(2, "MAR <- %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - mar[7], mar[6], mar[5], mar[4], - mar[3], mar[2], mar[1], mar[0]); + putlog(2, "MAR <- $%08x'%08x", (uint32)(mar >> 32), (uint32)mar); } } } @@ -1783,7 +1779,7 @@ RTL8019ASDevice::PeekCURR() const uint32 RTL8019ASDevice::PeekMAR(int n) const { - return mar[n]; + return (mar >> (n * 8)) & 0xff; } uint32 @@ -2028,24 +2024,11 @@ RTL8019ASDevice::ChangeState(State newst switch (newstate) { case State::Normal: - { - uint64 filter; - filter = ((uint64)mar[0] << 0) - | ((uint64)mar[1] << 8) - | ((uint64)mar[2] << 16) - | ((uint64)mar[3] << 24) - | ((uint64)mar[4] << 32) - | ((uint64)mar[5] << 40) - | ((uint64)mar[6] << 48) - | ((uint64)mar[7] << 56); - hostnet->SetMyAddr(par); - hostnet->SetMCastFilter(filter); hostnet->EnableRx(true); break; - } case State::Stop: - if (tx_in_progress || rx_packet.length != 0) { + if (tx_in_progress || rx_packet.Length() != 0) { // 処理中があれば、処理が終わるのを待つ。 // (送信または受信処理完了時に Stop にする) newstate = State::StopInProgress; @@ -2084,12 +2067,12 @@ RTL8019ASDevice::Transmit() tsr = 0; // 転送イベントを起こすだけ。 - tx_event.time = 0; + tx_event->time = 0; scheduler->StartEvent(tx_event); // LED イベントは止まっていれば動かす。 - if (txled_event.IsRunning() == false) { - txled_event.time = 0; + if (txled_event->IsRunning() == false) { + txled_event->time = 0; scheduler->StartEvent(txled_event); } } @@ -2098,13 +2081,13 @@ RTL8019ASDevice::Transmit() // TXP=1 で呼ばれて、ページごとにパケットにコピーする。 // TBCR で指定された長さを全部コピーしたらホストに送信。 void -RTL8019ASDevice::TXEvent(Event& ev) +RTL8019ASDevice::TXEvent(Event *ev) { // 今回処理する分 uint count = std::min((uint)transmit_byte_count, 256u); - if (count == 0 && tx_packet.length != 0) { + if (count == 0 && tx_packet.Length() != 0) { // 前回でコピーが完了していればここで送信。 - putlog(3, "TXEvent Send %u bytes", tx_packet.length); + putlog(3, "TXEvent Send %u bytes", tx_packet.Length()); hostnet->Tx(tx_packet); // 送信完了。 @@ -2136,7 +2119,7 @@ RTL8019ASDevice::TXEvent(Event& ev) // 転送にかかった時間を模しておく。 // 時間は適当。10Mbps なので 1バイトあたり 1usec とする。 - tx_event.time = count * 1_usec; + tx_event->time = usec_to_tsec(count); scheduler->StartEvent(tx_event); } @@ -2147,8 +2130,8 @@ RTL8019ASDevice::RxMessage(MessageID msg // 受信イベントが止まっていれば動かす。 // 受信イベントがすでに動いていれば、1パケット受信完了後に // ホストキューを確認するので、ここでは何もしなくてよい。 - if (rx_event.IsRunning() == false) { - rx_event.time = 0; + if (rx_event->IsRunning() == false) { + rx_event->time = 0; scheduler->StartEvent(rx_event); } } @@ -2162,11 +2145,11 @@ RTL8019ASDevice::RxMessage(MessageID msg // len != 0, remain < len : 受信パケットのコピー (2ページ目以降) // len != 0, remain == 0 : 受信パケットのコピー完了直後。 void -RTL8019ASDevice::RXEvent(Event& ev) +RTL8019ASDevice::RXEvent(Event *ev) { uint remain; - if (rx_packet.length == 0) { + if (rx_packet.Length() == 0) { // パケットが空の時に呼ばれたら、 // ホストキューから1パケット取り出してみる。 if (hostnet->Rx(&rx_packet) == false) { @@ -2181,8 +2164,8 @@ RTL8019ASDevice::RXEvent(Event& ev) // 受信 LED イベントが止まっていれば動かす。 // 取り出して、破棄するかもしれないより前。 - if (rxled_event.IsRunning() == false) { - rxled_event.time = 0; + if (rxled_event->IsRunning() == false) { + rxled_event->time = 0; scheduler->StartEvent(rxled_event); } @@ -2199,7 +2182,7 @@ RTL8019ASDevice::RXEvent(Event& ev) } } - assert(rx_packet.length != 0); + assert(rx_packet.Length() != 0); remain = rx_packet.GetRemain(); if (remain != 0) { // 実際に書き込む前に、これから書き込むページ(local_addr) が @@ -2220,7 +2203,7 @@ RTL8019ASDevice::RXEvent(Event& ev) goto discard; } - if (remain == rx_packet.length) { + if (remain == rx_packet.Length()) { // 初回処理 RXHead(); } @@ -2235,7 +2218,7 @@ RTL8019ASDevice::RXEvent(Event& ev) // この場合も、ホストキューから次のパケットを引き取る作業は必要。 // XXX 間隔は適当 rx_packet.Clear(); - ev.time = 1_usec; + ev->time = 1_usec; scheduler->RestartEvent(ev); } @@ -2245,7 +2228,7 @@ void RTL8019ASDevice::RXHead() { // 先に、このパケットの次のページ位置を求めて覚えておく。 - next_page_addr = local_addr + 4 + rx_packet.length; + next_page_addr = local_addr + 4 + rx_packet.Length(); next_page_addr = roundup(next_page_addr, 256); if (next_page_addr >= pstop_addr) { next_page_addr = pstart_addr + (next_page_addr - pstop_addr); @@ -2260,7 +2243,7 @@ RTL8019ASDevice::RXHead() // 1ページ埋めるかパケットをコピーし終えたら次へ。 // (初回もヘッダ書き込みに続いて呼ばれる) void -RTL8019ASDevice::RXCopy(Event& ev, uint remain) +RTL8019ASDevice::RXCopy(Event *ev, uint remain) { // パケットをこのページにコピー。 // 今回処理する分はパケットの残りとページの残りの小さいほう。 @@ -2284,7 +2267,7 @@ RTL8019ASDevice::RXCopy(Event& ev, uint // 転送にかかった時間を模しておく。 // 時間は適当。10Mbps なので 1バイトあたり 1usec とする。 - ev.time = count * 1_usec; + ev->time = usec_to_tsec(count); scheduler->RestartEvent(ev); } @@ -2293,13 +2276,17 @@ RTL8019ASDevice::RXCopy(Event& ev, uint // ストップ待ちでなければ再び RXEvent() イベントを呼び、 // 次パケットの処理を継続する。 void -RTL8019ASDevice::RXDone(Event& ev) +RTL8019ASDevice::RXDone(Event *ev) { // 前回でコピーが完了していればここで通知。 - putlog(3, "RXDone Received %u bytes", rx_packet.length); + uint length = rx_packet.Length(); + putlog(3, "RXDone Received %u bytes", length); // 受信ヘッダに書き込む前に RSR を更新 rsr |= RTL8019::RSR_PRX; + if ((rx_packet.Peek(0) & 0x01)) { + rsr |= RTL8019::RSR_PHY; + } // 念のためエラービットをクリア (DP83901A.pdf) rsr &= ~(RTL8019::RSR_MPA | RTL8019::RSR_FAE | @@ -2324,8 +2311,8 @@ RTL8019ASDevice::RXDone(Event& ev) uint16 addr = current_page_addr; WriteRAM(addr++, rsr); WriteRAM(addr++, next_page_addr >> 8); - WriteRAM(addr++, rx_packet.length & 0xff); - WriteRAM(addr++, rx_packet.length >> 8); + WriteRAM(addr++, length & 0xff); + WriteRAM(addr++, length >> 8); // CURR を次受信ページに更新。残り転送バイトが 0 になった時点で // local_addr は次ページ先頭に繰り上げてある。 @@ -2342,22 +2329,84 @@ RTL8019ASDevice::RXDone(Event& ev) ChangeState(State::Stop); } else { // そうでなければ、次の受信を試す。 - // (rx_packet.length == 0 で RXEvent() を呼ぶとパケット受信となる) + // (rx_packet.Length() == 0 で RXEvent() を呼ぶとパケット受信となる) // どのくらいか待つ? 値は適当 - ev.time = 100_usec; + ev->time = 100_usec; scheduler->RestartEvent(ev); } } +// この宛先アドレスを受信するかどうか。 +// これは HostNet スレッドで呼ばれる。 +int +RTL8019ASDevice::HWAddrFilter(const MacAddr& dstaddr) const +{ + // RTL8019AS.pdf では詳細不明だが、 + // DP83901A.pdf には、完全なプロミスキャスにするには AB, AM, PRO 全部 + // 立ててさらにマルチキャストハッシュを全部 1 にしろ、と注釈があるので、 + // - PRO は自分宛て以外のユニキャストを受け取るかどうか、 + // - AM は、ハッシュで accept になったマルチキャストを受け取るか + // マルチキャストを一切受け取らないか、 + // - AB はブロードキャストを受け取るかどうか、 + // の独立したビットのようだ。 + + if (dstaddr.IsUnicast()) { + if (promisc_mode == false) { + if (dstaddr != par) { + return HPF_DROP_UNICAST; + } + } + } else { + if (dstaddr.IsBroadcast()) { + if (accept_bcast == false) { + // XXX 選択肢がまだない + return HPF_DROP_MULTICAST; + } + } else { + if (accept_mcast == false) { + return HPF_DROP_MULTICAST; + } + + // マルチキャスト + // + // RTL8019AS のマルチキャストフィルタ(ハッシュ) は宛先 MAC + // アドレスの CRC (32ビット) のうち上位6ビットを pos として、 + // MAR の下から pos ビット目が立っていれば受理する、というもの。 + // + // 31 30 29 28 27 26 25 24 0 + // +---+---+---+---+---+---+---+---+-- --+ + // CRC32(dstaddr) = | p5| p4| p3| p2| p1| p0| X X | .. | + // +---+---+---+---+---+---+---+---+-- --+ + // + // +---+---+---+---+---+---+ + // pos = | p5| p4| p3| p2| p1| p0| + // +---+---+---+---+---+---+ + + uint32 crc = EthernetDevice::CRC32(dstaddr); + uint pos = crc >> 26; + bool mcast_pass = (mar & (1ULL << pos)); + putmsg(2, "mcast %02x:%02x:%02x:%02x:%02x:%02x pos=%u %s", + dstaddr[0], dstaddr[1], dstaddr[2], + dstaddr[3], dstaddr[4], dstaddr[5], + pos, (mcast_pass ? "pass" : "drop")); + if (mcast_pass == false) { + return HPF_DROP_MULTICAST; + } + } + } + + return HPF_PASS; +} + // 送信 LED イベント void -RTL8019ASDevice::TXLedEvent(Event& ev) +RTL8019ASDevice::TXLedEvent(Event *ev) { if (tx_led == false) { // 消灯中だったら、次は 6msec 点灯 tx_led = true; - ev.time = 6_msec; + ev->time = 6_msec; scheduler->RestartEvent(ev); } else { // 点灯中だったら @@ -2365,7 +2414,7 @@ RTL8019ASDevice::TXLedEvent(Event& ev) // - 送信中でなければここで終わり if (tx_in_progress) { tx_led = false; - ev.time = 100_msec; + ev->time = 100_msec; scheduler->RestartEvent(ev); } } @@ -2373,20 +2422,20 @@ RTL8019ASDevice::TXLedEvent(Event& ev) // 受信 LED イベント void -RTL8019ASDevice::RXLedEvent(Event& ev) +RTL8019ASDevice::RXLedEvent(Event *ev) { if (rx_led == false) { // 消灯中だったら、次は 6msec 点灯 rx_led = true; - ev.time = 6_msec; + ev->time = 6_msec; scheduler->RestartEvent(ev); } else { // 点灯中だったら // - 受信中なら次は 100msec 消灯 // - 受信中でなければここで終わり - if (rx_packet.length != 0) { + if (rx_packet.Length() != 0) { rx_led = false; - ev.time = 100_msec; + ev->time = 100_msec; scheduler->RestartEvent(ev); } }