--- nono/vm/virtio_base.h 2026/04/29 17:05:24 1.1.1.1 +++ nono/vm/virtio_base.h 2026/04/29 17:05:28 1.1.1.2 @@ -12,12 +12,14 @@ #include "device.h" #include "message.h" +#include "monitor.h" #include "thread.h" #include #include class InterruptDevice; class MainbusDevice; +class MainRAMDevice; class TextScreen; class VirtIOThread; class VirtQDesc; @@ -27,43 +29,57 @@ class VirtQueue public: VirtQueue(int idx_, const std::string& name_, int num_max_); + // idx_ % num を返す。 + // num が 0 なら何でもいいので死なないように 0 を返す。 + uint Mod(uint idx_) const { + if (__predict_false(num == 0)) { + return 0; + } + return idx_ % num; + } + uint32 last_avail_idx {}; - int idx {}; // 自身が何番目か + uint idx {}; // 自身が何番目か std::string name {}; // キュー名(仕様から決まる) uint32 desc {}; // QUEUE_DESC (下位32ビットのみ) uint32 driver {}; // QUEUE_DRIVER (下位32ビットのみ) uint32 device {}; // QUEUE_DEVICE (下位32ビットのみ) - int num {}; // QUEUE_NUM (合意できたディスクリプタ数) - int num_max {}; // QUEUE_NUM の上限 + uint num {}; // QUEUE_NUM (合意できたディスクリプタ数) + uint num_max {}; // QUEUE_NUM の上限 uint32 ready {}; // QUEUE_READY }; class VirtIOSeg { public: - uint32 addr {}; // バッファアドレス (ゲストアドレス) - uint32 len {}; // バッファ長 + uint32 addr {}; // セグメントアドレス (ゲストアドレス) + uint32 pos {}; // このセグメントのチェイン先頭からの位置 + uint32 len {}; // このセグメント長 - VirtIOSeg(uint32 addr_, uint32 len_) - : addr(addr_), len(len_) + VirtIOSeg(uint32 addr_, uint32 pos_, uint32 len_) + : addr(addr_), pos(pos_), len(len_) { } }; -// ディスクリプタチェインの基本クラス +// ディスクリプタチェイン。 +// ファイルハンドルのようなものも兼ねている。 +// 元の仕様からシーケンシャルアクセスを想定しているようなので、ここでも +// シーケンシャルアクセスを前提とする。そのため pos が UsedRing に書き込む +// バイト数になる。 class VirtIOReq { public: VirtQueue *q {}; uint32 idx {}; // このディスクリプタチェインの先頭インデックス uint32 len {}; // このディスクリプタチェインの総バイト数 + uint32 pos {}; // 現在位置 (Used としても使用する) std::vector buf {}; // バッファセグメント - int curseg {}; // 書き込み位置、現在のセグメント - int offset {}; // 書き込み位置、セグメント内のオフセット + int curseg {}; // 現在のセグメント (buf[] のインデックス) }; // VirtIO 基本クラス @@ -82,7 +98,7 @@ class VirtIODevice : public IODevice static const uint32 baseaddr = 0xff070000; public: - VirtIODevice(int objid_, int slot_); + VirtIODevice(uint objid_, uint slot_); ~VirtIODevice() override; bool Create() override; @@ -90,29 +106,38 @@ class VirtIODevice : public IODevice bool Init() override; void ResetHard(bool poweron) override; - busdata Read8(uint32 addr) override; - busdata Read16(uint32 addr) override; - busdata Read32(uint32 addr) override; - busdata Write8(uint32 addr, uint32 data) override; - busdata Write16(uint32 addr, uint32 data) override; - busdata Write32(uint32 addr, uint32 data) override; - busdata Peek8(uint32 addr) override; - // QUEUE_NOTIFY の処理 (裏スレッドから呼ばれる) - void QueueNotify(int idx); + void QueueNotify(uint idx); protected: + // BusIO インタフェース + static const uint32 NPORT = 0x200 >> 2; + busdata ReadPort(uint32 offset); + 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; + void Reset(); virtual uint32 GetReg(uint32 addr) const; virtual void QueueReady(); // ディスクリプタを一つ処理する。 - virtual void ProcessDesc(VirtQueue *) = 0; + virtual void ProcessDesc(VirtIOReq&) = 0; + // ディスクリプタを読んでチェインを用意する。 + void StartDesc(VirtIOReq&); // ディスクリプタを更新する。 - void CommitDesc(VirtQueue *, uint32 idx, uint32 len); + void CommitDesc(VirtIOReq&); + + // ディスクリプタアクセス + uint32 ReqReadU8(VirtIOReq&); + uint32 ReqReadLE16(VirtIOReq&); + uint64 ReqReadLE32(VirtIOReq&); + bool ReqReadLE32(VirtIOReq&, uint32 *); + bool ReqReadLE64(VirtIOReq&, uint64 *); + bool ReqWriteU8(VirtIOReq&, uint32 data); // 裏スレッドからの処理完了メッセージ void DoneMessage(MessageID, uint32); @@ -133,19 +158,20 @@ class VirtIODevice : public IODevice uint32 PeekLE16(uint32 addr) const; uint32 PeekLE32(uint32 addr) const; - uint32 ReadDesc(const VirtQueue *, VirtQDesc *desc, uint32 idx); - void AddDataSegment(VirtIOReq *, uint32 addr, uint32 len, const char *); - bool ReqAppendByte(VirtIOReq *, uint32 data); - // DEVICE_FEATURES の feature 番目のビットを立てる。初期化用。 void SetDeviceFeatures(int feature); // DEVICE_FEATURES の feature 番目の名前を返す。 - virtual const char *GetFeatureName(int feature) const; + virtual const char *GetFeatureName(uint feature) const; // DRIVER_FEATURES の feature 番目のビットが立っていれば true。 bool GetDriverFeatures(int feature) const; - int slot {}; // VirtIO のスロット番号 (0-127) + private: + // 間接ディスクリプタを追加する。 + void AddIndirectDesc(VirtIOReq&, uint32 addr, uint32 len); + + protected: + uint slot {}; // VirtIO のスロット番号 (0-127) uint32 device_id {}; // DEVICE_ID uint32 vendor_id {}; // VENDOR_ID @@ -156,8 +182,6 @@ class VirtIODevice : public IODevice std::array device_features {}; // DEVICE_FEATURES std::array driver_features {}; // DRIVER_FEATURES - uint32 queue_num {}; // QUEUE_NUM - // VirtQueue。継承先で個数が決まっている。 std::vector vqueues {}; // QUEUE_SEL の値。 @@ -178,6 +202,9 @@ class VirtIODevice : public IODevice InterruptDevice *interrupt {}; MainbusDevice *mainbus {}; + MainRAMDevice *mainram {}; + + Monitor monitor { this }; }; // VirtIO 空きスロット用 @@ -188,9 +215,12 @@ class VirtIONoneDevice : public IODevice VirtIONoneDevice(); ~VirtIONoneDevice() override; - busdata Read32(uint32 addr) override; - busdata Write32(uint32 addr, uint32 data) override; - busdata Peek8(uint32 addr) override; + protected: + // BusIO インタフェース + static const uint32 NPORT = 0x200 >> 2; + busdata ReadPort(uint32 offset); + busdata WritePort(uint32 offset, uint32 data); + busdata PeekPort(uint32 offset); }; // 裏スレッド @@ -201,18 +231,18 @@ class VirtIOThread : public ThreadDevice protected: // REQ_QUEUE はキュー1本に1ビットずつ割り当てているので現状最大31まで。 static const uint32 REQ_TERMINATE = 0x80000000; // スレッド終了指示 - static constexpr uint32 REQ_QUEUE(int idx) { // QUEUE_NOTIFY 指示 + static constexpr uint32 REQ_QUEUE(uint idx) { // QUEUE_NOTIFY 指示 return (1U << idx); } public: - VirtIOThread(VirtIODevice *parent_); + explicit VirtIOThread(VirtIODevice *parent_); ~VirtIOThread() override; void Terminate() override; // ゲストからの QUEUE_NOTIFY 要求 - void RequestQueueNotify(int); + void RequestQueueNotify(uint); private: void ThreadRun() override;