--- nono/vm/virtio_base.h 2026/04/29 17:05:28 1.1.1.2 +++ nono/vm/virtio_base.h 2026/04/29 17:05:59 1.1.1.5 @@ -12,7 +12,7 @@ #include "device.h" #include "message.h" -#include "monitor.h" +#include "missing_bswap.h" #include "thread.h" #include #include @@ -21,13 +21,15 @@ class InterruptDevice; class MainbusDevice; class MainRAMDevice; class TextScreen; +class VirtIODevice; class VirtIOThread; class VirtQDesc; class VirtQueue { public: - VirtQueue(int idx_, const std::string& name_, int num_max_); + VirtQueue(VirtIODevice *parent_, int idx_, const std::string& name_, + int num_max_); // idx_ % num を返す。 // num が 0 なら何でもいいので死なないように 0 を返す。 @@ -49,6 +51,15 @@ class VirtQueue uint num {}; // QUEUE_NUM (合意できたディスクリプタ数) uint num_max {}; // QUEUE_NUM の上限 + + // QUEUE_READY の設定と取得。 + // Get は副作用を起こしてはいけない。 + void SetReady(uint32 val); + uint32 GetReady() const noexcept { return ready; } + + private: + VirtIODevice *parent {}; + uint32 ready {}; // QUEUE_READY }; @@ -56,11 +67,10 @@ class VirtIOSeg { public: uint32 addr {}; // セグメントアドレス (ゲストアドレス) - uint32 pos {}; // このセグメントのチェイン先頭からの位置 uint32 len {}; // このセグメント長 - VirtIOSeg(uint32 addr_, uint32 pos_, uint32 len_) - : addr(addr_), pos(pos_), len(len_) + VirtIOSeg(uint32 addr_, uint32 len_) + : addr(addr_), len(len_) { } }; @@ -68,24 +78,53 @@ class VirtIOSeg // ディスクリプタチェイン。 // ファイルハンドルのようなものも兼ねている。 // 元の仕様からシーケンシャルアクセスを想定しているようなので、ここでも -// シーケンシャルアクセスを前提とする。そのため pos が UsedRing に書き込む +// シーケンシャルアクセスを前提とする。そのため pos() が UsedRing に書き込む // バイト数になる。 class VirtIOReq { public: VirtQueue *q {}; uint32 idx {}; // このディスクリプタチェインの先頭インデックス - uint32 len {}; // このディスクリプタチェインの総バイト数 - uint32 pos {}; // 現在位置 (Used としても使用する) - std::vector buf {}; // バッファセグメント - int curseg {}; // 現在のセグメント (buf[] のインデックス) + int rseg {}; // 現在の読み込みセグメントインデックス + uint32 roff {}; // 読み込み位置(セグメント内の相対位置) + std::vector rbuf {}; // 読み込み用セグメント + uint32 rlen {}; // 読み込みセグメントの総バイト数 + + int wseg {}; // 現在の書き込みセグメントインデックス + uint32 woff {}; // 書き込み位置(セグメント内の相対位置) + std::vector wbuf {}; // 書き込み用セグメント + uint32 wlen {}; // 書き込みセグメントの総バイト数 + + // このディスクリプタチェインの総バイト数。 + uint32 totallen() const noexcept { return rlen + wlen; } + + // 読み込みセグメントの残りバイト数。 + uint32 rremain() const { return rlen - rpos(); } + + // 読み込みセグメントの残りをすべて読み捨てる。 + void rskip() { + rseg = rbuf.size(); + roff = 0; + } + + // 読み込みセグメントの先頭からの現在位置を返す。 + uint32 rpos() const; + // 書き込みセグメントの先頭からの現在位置を返す。 + uint32 wpos() const; + // 処理した総バイト数を返す。 + uint32 pos() const { return rpos() + wpos(); } + + // 読み込みまたは書き込みが末尾に到達していれば true を返す。 + bool reof() const { return rseg >= rbuf.size(); } + bool weof() const { return wseg >= wbuf.size(); } }; // VirtIO 基本クラス class VirtIODevice : public IODevice { using inherited = IODevice; + friend class VirtQueue; protected: // 仕様書には名前が出てこないけど上限 @@ -116,12 +155,12 @@ class VirtIODevice : public IODevice busdata WritePort(uint32 offset, uint32 data); busdata PeekPort(uint32 offset); - int MonitorUpdateDev(TextScreen&, int y) const; - int MonitorUpdateVirtQueue(TextScreen&, int y, const VirtQueue&) const; - int MonitorUpdateVirtQDesc(TextScreen&, int y, const VirtQueue&) const; + int MonitorScreenDev(TextScreen&, int y) const; + int MonitorScreenVirtQueue(TextScreen&, int y, const VirtQueue&) const; + int MonitorScreenVirtQDesc(TextScreen&, int y, const VirtQueue&) const; void Reset(); virtual uint32 GetReg(uint32 addr) const; - virtual void QueueReady(); + virtual void QueueReadyChanged(VirtQueue *); // ディスクリプタを一つ処理する。 virtual void ProcessDesc(VirtIOReq&) = 0; @@ -135,9 +174,15 @@ class VirtIODevice : public IODevice uint32 ReqReadU8(VirtIOReq&); uint32 ReqReadLE16(VirtIOReq&); uint64 ReqReadLE32(VirtIOReq&); + uint32 ReqReadBE16(VirtIOReq& req) { return bswap16(ReqReadLE16(req)); } + uint32 ReqReadBE32(VirtIOReq& req) { return bswap32(ReqReadLE32(req)); } bool ReqReadLE32(VirtIOReq&, uint32 *); bool ReqReadLE64(VirtIOReq&, uint64 *); bool ReqWriteU8(VirtIOReq&, uint32 data); + bool ReqWriteLE16(VirtIOReq&, uint32 data); + bool ReqWriteLE32(VirtIOReq&, uint32 data); + uint32 ReqReadRegion(VirtIOReq&, uint8 *dst, uint32 dstlen); + uint32 ReqWriteRegion(VirtIOReq&, const uint8 *src, uint32 srclen); // 裏スレッドからの処理完了メッセージ void DoneMessage(MessageID, uint32); @@ -204,7 +249,7 @@ class VirtIODevice : public IODevice MainbusDevice *mainbus {}; MainRAMDevice *mainram {}; - Monitor monitor { this }; + Monitor *monitor {}; }; // VirtIO 空きスロット用