File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / ethernet.cpp
Revision 1.1.1.12 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:46 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, v026, v025, v024, HEAD
nono 1.4.0

//
// nono
// Copyright (C) 2020 nono project
// Licensed under nono-license.txt
//

//
// Ethernet 基本クラス
//

#if !defined(SELFTEST)
#include "ethernet.h"
#include "config.h"
#include "hostnet.h"
#include "scheduler.h"

// コンストラクタ
EthernetDevice::EthernetDevice(uint objid_)
	: inherited(objid_)
{
}

// デストラクタ
EthernetDevice::~EthernetDevice()
{
	if ((bool)hostnet) {
		hostnet->ResetRxCallback();
	}
}

// 動的なコンストラクション
bool
EthernetDevice::Create()
{
	// ホストドライバを作成してこのデバイスと紐付ける。
	// ポート名は継承先ごとに Init() で設定している。
	int n = GetId() - OBJ_ETHERNET0;
	try {
		hostnet.reset(new HostNetDevice(this, n, ""));
	} catch (...) { }
	if ((bool)hostnet == false) {
		warnx("Failed to initialize HostNetDevice(%u) at %s", n, __method__);
		return false;
	}

	auto func = ToDeviceCallback(&EthernetDevice::HostRxCallback);
	hostnet->SetRxCallback(func, 0);

	return true;
}

// これは Host スレッドから呼ばれる
void
EthernetDevice::HostRxCallback(uint32 dummy)
{
	// スレッドを超えるためにメッセージを投げる
	int n = GetId() - OBJ_ETHERNET0;
	scheduler->SendMessage(MessageID::HOSTNET_RX(n));
}

// 設定ファイルから MAC アドレスを読み込む。
// MAC アドレスを保持するデバイスが呼び出すこと。MAC アドレスを保持する
// デバイスがイーサネットデバイスとは限らず、例えば LANCE を採用している
// 機種ではたいてい ROM か誰かが MAC アドレスを持っている。
//
// 引数 accept_rom が true なら、設定 ethernet-macaddr=rom を許可する。
// これは (お手持ちの実機) ROM イメージが MAC アドレスを保持しているため、
// 指定(や生成)不要なケースで指定できる (prom.cpp 参照)。
// 引数 accept_rom が false で、設定値に "rom" が指定されるとエラーにする。
//
// "rom" が指定されて許可されている場合 mac は触らず true を返す。
// MAC アドレスが指定されているか自動生成したかで取得できれば mac に格納して
// true を返す。それ以外の場合は、エラーメッセージを表示して false を返す。
/*static*/ bool
EthernetDevice::GetConfigMacAddr(uint n, MacAddr *mac, bool accept_rom)
{
	std::string keyname = string_format("ethernet%u-macaddr", n);
	const ConfigItem& item = gConfig->Find(keyname);
	const std::string& val = item.AsString();

	if (val == "rom") {
		// ROM に書いてあるのを使う。
		if (accept_rom) {
			return true;
		} else {
			item.Err("\"rom\" cannot be specified in this vmtype");
			return false;
		}
	} else {
		if (val == "auto") {
			// 自動生成。
			// 出来れば生成したのを覚えといて、次からそれを使いたい。
			if (0) {
			} else {
				mac->Generate();
			}
		} else {
			// ユーザ指定
			if (mac->FromString(val) == false) {
				item.Err("Invalid MAC address");
				return false;
			}
		}
	}

	return true;
}

#endif // !SELFTEST

// CRC32 を計算する。
//
// CRC と言ってもおそらく5つのパラメータによって定まる亜種が多数あるが、
// Ethernet で使われる CRC32 はおそらく以下のもの。
//  初期値: 0xffffffff
//  多項式: 0x04c11db6
//  RefIn : false
//  RefOut: false (出力をビットリバースしない)
//  XorOut: false (出力を XOR しない)
//
// NetBSD の src/sys/net/if_ethersubr.c にある ether_crc32_be() がこれと同じ。
//
// その隣にある ether_crc32_le() は
//  初期値: 0xffffffff
//  多項式: 0xedb88320
//  RefIn : true
//  RefOut: false (出力をビットリバースしない)
//  XorOut: false (出力を XOR しない)
// というパラメータだが、RefIn と多項式のビットが反転しているだけなので
// 結果をビットリバースすれば同じものになる。
//
// ちなみに ether_crc32_* の_le, _be はエンディアンではなく、どっち向きに
// 処理するかを示しており、名前が紛らわしい。
/*static*/ uint32
EthernetDevice::CRC32(const uint8 *buf, size_t buflen)
{
	static const uint32 CRC_POLY = 0x04c11db6;
	uint32 crc;
	uint32 cy;

	crc = 0xffffffff;
	for (size_t i = 0; i < buflen; i++) {
		uint32 s = buf[i];
		for (size_t j = 0; j < 8; j++) {
			cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01);
			crc <<= 1;
			s >>= 1;
			if (cy) {
				crc = (crc ^ CRC_POLY) | cy;
			}
		}
	}

	return crc;
}

// MAC アドレスの CRC32 を計算する限定版。
// 6バイトが uint64 にリトルエンディアン的に格納されていると分かっている。
/*static*/ uint32
EthernetDevice::CRC32(const MacAddr& mac)
{
	static const uint32 CRC_POLY = 0x04c11db6;
	uint32 crc;
	uint64 s = mac.Get();

	crc = 0xffffffff;
	for (size_t i = 0; i < mac.size() * 8; i++) {
		uint32 cy = ((crc & 0x80000000U) ? 0x01 : 0x00) ^ (s & 0x01);
		crc <<= 1;
		s >>= 1;
		if (cy) {
			crc = (crc ^ CRC_POLY) | cy;
		}
	}

	return crc;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.