Annotation of nono/vm/virtio_base.h, revision 1.1.1.5

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2024 nono project
                      4: // Licensed under nono-license.txt
                      5: //
                      6: 
                      7: //
                      8: // VirtIO
                      9: //
                     10: 
                     11: #pragma once
                     12: 
                     13: #include "device.h"
                     14: #include "message.h"
1.1.1.5 ! root       15: #include "missing_bswap.h"
1.1       root       16: #include "thread.h"
                     17: #include <array>
                     18: #include <condition_variable>
                     19: 
                     20: class InterruptDevice;
                     21: class MainbusDevice;
1.1.1.2   root       22: class MainRAMDevice;
1.1       root       23: class TextScreen;
1.1.1.3   root       24: class VirtIODevice;
1.1       root       25: class VirtIOThread;
                     26: class VirtQDesc;
                     27: 
                     28: class VirtQueue
                     29: {
                     30:  public:
1.1.1.3   root       31:        VirtQueue(VirtIODevice *parent_, int idx_, const std::string& name_,
                     32:                int num_max_);
1.1       root       33: 
1.1.1.2   root       34:        // idx_ % num を返す。
                     35:        // num が 0 なら何でもいいので死なないように 0 を返す。
                     36:        uint Mod(uint idx_) const {
                     37:                if (__predict_false(num == 0)) {
                     38:                        return 0;
                     39:                }
                     40:                return idx_ % num;
                     41:        }
                     42: 
1.1       root       43:        uint32 last_avail_idx {};
                     44: 
1.1.1.2   root       45:        uint idx {};                    // 自身が何番目か
1.1       root       46:        std::string name {};    // キュー名(仕様から決まる)
                     47: 
                     48:        uint32 desc {};                 // QUEUE_DESC (下位32ビットのみ)
                     49:        uint32 driver {};               // QUEUE_DRIVER (下位32ビットのみ)
                     50:        uint32 device {};               // QUEUE_DEVICE (下位32ビットのみ)
                     51: 
1.1.1.2   root       52:        uint num {};                    // QUEUE_NUM (合意できたディスクリプタ数)
                     53:        uint num_max {};                // QUEUE_NUM の上限
1.1.1.3   root       54: 
                     55:        // QUEUE_READY の設定と取得。
                     56:        // Get は副作用を起こしてはいけない。
                     57:        void SetReady(uint32 val);
                     58:        uint32 GetReady() const noexcept { return ready; }
                     59: 
                     60:  private:
                     61:        VirtIODevice *parent {};
                     62: 
1.1       root       63:        uint32 ready {};                // QUEUE_READY
                     64: };
                     65: 
                     66: class VirtIOSeg
                     67: {
                     68:  public:
1.1.1.2   root       69:        uint32 addr {};                 // セグメントアドレス (ゲストアドレス)
                     70:        uint32 len {};                  // このセグメント長
1.1       root       71: 
1.1.1.4   root       72:        VirtIOSeg(uint32 addr_, uint32 len_)
                     73:                : addr(addr_), len(len_)
1.1       root       74:        {
                     75:        }
                     76: };
                     77: 
1.1.1.2   root       78: // ディスクリプタチェイン。
                     79: // ファイルハンドルのようなものも兼ねている。
                     80: // 元の仕様からシーケンシャルアクセスを想定しているようなので、ここでも
1.1.1.4   root       81: // シーケンシャルアクセスを前提とする。そのため pos() が UsedRing に書き込む
1.1.1.2   root       82: // バイト数になる。
1.1       root       83: class VirtIOReq
                     84: {
                     85:  public:
                     86:        VirtQueue *q {};
                     87:        uint32 idx {};                  // このディスクリプタチェインの先頭インデックス
                     88: 
1.1.1.4   root       89:        int    rseg {};                 // 現在の読み込みセグメントインデックス
                     90:        uint32 roff {};                 // 読み込み位置(セグメント内の相対位置)
                     91:        std::vector<VirtIOSeg> rbuf {}; // 読み込み用セグメント
                     92:        uint32 rlen {};                 // 読み込みセグメントの総バイト数
                     93: 
                     94:        int    wseg {};                 // 現在の書き込みセグメントインデックス
                     95:        uint32 woff {};                 // 書き込み位置(セグメント内の相対位置)
                     96:        std::vector<VirtIOSeg> wbuf {}; // 書き込み用セグメント
                     97:        uint32 wlen {};                 // 書き込みセグメントの総バイト数
                     98: 
                     99:        // このディスクリプタチェインの総バイト数。
                    100:        uint32 totallen() const noexcept { return rlen + wlen; }
                    101: 
                    102:        // 読み込みセグメントの残りバイト数。
                    103:        uint32 rremain() const { return rlen - rpos(); }
                    104: 
                    105:        // 読み込みセグメントの残りをすべて読み捨てる。
                    106:        void rskip() {
                    107:                rseg = rbuf.size();
                    108:                roff = 0;
                    109:        }
                    110: 
                    111:        // 読み込みセグメントの先頭からの現在位置を返す。
                    112:        uint32 rpos() const;
                    113:        // 書き込みセグメントの先頭からの現在位置を返す。
                    114:        uint32 wpos() const;
                    115:        // 処理した総バイト数を返す。
                    116:        uint32 pos() const { return rpos() + wpos(); }
                    117: 
                    118:        // 読み込みまたは書き込みが末尾に到達していれば true を返す。
                    119:        bool reof() const { return rseg >= rbuf.size(); }
                    120:        bool weof() const { return wseg >= wbuf.size(); }
1.1       root      121: };
                    122: 
                    123: // VirtIO 基本クラス
                    124: class VirtIODevice : public IODevice
                    125: {
                    126:        using inherited = IODevice;
1.1.1.3   root      127:        friend class VirtQueue;
1.1       root      128: 
                    129:  protected:
                    130:        // 仕様書には名前が出てこないけど上限
                    131:        static const uint MAX_FEATURES_SEL = 2;
                    132: 
                    133:        // モニタ幅
                    134:        static const int MONITOR_WIDTH = 75;
                    135: 
                    136:        // 動作には不要だがモニタに表示したいので…。
                    137:        static const uint32 baseaddr = 0xff070000;
                    138: 
                    139:  public:
1.1.1.2   root      140:        VirtIODevice(uint objid_, uint slot_);
1.1       root      141:        ~VirtIODevice() override;
                    142: 
                    143:        bool Create() override;
                    144:        void SetLogLevel(int loglevel_) override;
                    145:        bool Init() override;
                    146:        void ResetHard(bool poweron) override;
                    147: 
                    148:        // QUEUE_NOTIFY の処理 (裏スレッドから呼ばれる)
1.1.1.2   root      149:        void QueueNotify(uint idx);
1.1       root      150: 
                    151:  protected:
1.1.1.2   root      152:        // BusIO インタフェース
                    153:        static const uint32 NPORT = 0x200 >> 2;
                    154:        busdata ReadPort(uint32 offset);
                    155:        busdata WritePort(uint32 offset, uint32 data);
                    156:        busdata PeekPort(uint32 offset);
                    157: 
1.1.1.5 ! root      158:        int MonitorScreenDev(TextScreen&, int y) const;
        !           159:        int MonitorScreenVirtQueue(TextScreen&, int y, const VirtQueue&) const;
        !           160:        int MonitorScreenVirtQDesc(TextScreen&, int y, const VirtQueue&) const;
1.1.1.2   root      161:        void Reset();
1.1       root      162:        virtual uint32 GetReg(uint32 addr) const;
1.1.1.3   root      163:        virtual void QueueReadyChanged(VirtQueue *);
1.1       root      164: 
                    165:        // ディスクリプタを一つ処理する。
1.1.1.2   root      166:        virtual void ProcessDesc(VirtIOReq&) = 0;
1.1       root      167: 
1.1.1.2   root      168:        // ディスクリプタを読んでチェインを用意する。
                    169:        void StartDesc(VirtIOReq&);
1.1       root      170:        // ディスクリプタを更新する。
1.1.1.2   root      171:        void CommitDesc(VirtIOReq&);
                    172: 
                    173:        // ディスクリプタアクセス
                    174:        uint32 ReqReadU8(VirtIOReq&);
                    175:        uint32 ReqReadLE16(VirtIOReq&);
                    176:        uint64 ReqReadLE32(VirtIOReq&);
1.1.1.4   root      177:        uint32 ReqReadBE16(VirtIOReq& req) { return bswap16(ReqReadLE16(req)); }
                    178:        uint32 ReqReadBE32(VirtIOReq& req) { return bswap32(ReqReadLE32(req)); }
1.1.1.2   root      179:        bool ReqReadLE32(VirtIOReq&, uint32 *);
                    180:        bool ReqReadLE64(VirtIOReq&, uint64 *);
                    181:        bool ReqWriteU8(VirtIOReq&, uint32 data);
1.1.1.4   root      182:        bool ReqWriteLE16(VirtIOReq&, uint32 data);
                    183:        bool ReqWriteLE32(VirtIOReq&, uint32 data);
                    184:        uint32 ReqReadRegion(VirtIOReq&, uint8 *dst, uint32 dstlen);
                    185:        uint32 ReqWriteRegion(VirtIOReq&, const uint8 *src, uint32 srclen);
1.1       root      186: 
                    187:        // 裏スレッドからの処理完了メッセージ
                    188:        void DoneMessage(MessageID, uint32);
                    189:        // 処理完了
                    190:        void Done(VirtQueue *);
                    191: 
                    192:        void ChangeInterrupt();
                    193: 
                    194:        // メインバスアクセス
                    195:        uint32 ReadU8(uint32 addr);
                    196:        uint32 ReadLE16(uint32 addr);
                    197:        uint32 ReadLE32(uint32 addr);
                    198:        uint64 ReadLE64(uint32 addr);
                    199:        void WriteU8(uint32 addr, uint32 data);
                    200:        void WriteLE16(uint32 addr, uint32 data);
                    201:        void WriteLE32(uint32 addr, uint32 data);
                    202:        void WriteLE64(uint32 addr, uint64 data);
                    203:        uint32 PeekLE16(uint32 addr) const;
                    204:        uint32 PeekLE32(uint32 addr) const;
                    205: 
                    206:        // DEVICE_FEATURES の feature 番目のビットを立てる。初期化用。
                    207:        void SetDeviceFeatures(int feature);
                    208:        // DEVICE_FEATURES の feature 番目の名前を返す。
1.1.1.2   root      209:        virtual const char *GetFeatureName(uint feature) const;
1.1       root      210: 
                    211:        // DRIVER_FEATURES の feature 番目のビットが立っていれば true。
                    212:        bool GetDriverFeatures(int feature) const;
                    213: 
1.1.1.2   root      214:  private:
                    215:        // 間接ディスクリプタを追加する。
                    216:        void AddIndirectDesc(VirtIOReq&, uint32 addr, uint32 len);
                    217: 
                    218:  protected:
                    219:        uint slot {};                           // VirtIO のスロット番号 (0-127)
1.1       root      220: 
                    221:        uint32 device_id {};            // DEVICE_ID
                    222:        uint32 vendor_id {};            // VENDOR_ID
                    223:        uint32 device_status {};        // STATUS
                    224: 
                    225:        uint32 device_sel {};           // DEVICE_FEATURES_SEL
                    226:        uint32 driver_sel {};           // DRIVER_FEATURES_SEL
                    227:        std::array<uint32, 2> device_features {};       // DEVICE_FEATURES
                    228:        std::array<uint32, 2> driver_features {};       // DRIVER_FEATURES
                    229: 
                    230:        // VirtQueue。継承先で個数が決まっている。
                    231:        std::vector<VirtQueue> vqueues {};
                    232:        // QUEUE_SEL の値。
                    233:        uint32 queue_sel {};
                    234:        // QUEUE_SEL で選択されている現在の VirtQueue。選択されてなければ NULL。
                    235:        VirtQueue *vq {};
                    236: 
                    237:        uint32 intr_status {};                  // INTERRUPT_STATUS
                    238: 
                    239:        // 0x100 以降の領域
                    240:        std::array<uint8, 0x100> device_config {};
                    241: 
                    242:        char intrname[10] {};                   // 割り込み名
                    243: 
                    244:        MessageID msgid {};                             // 完了通知のメッセージ ID
                    245: 
                    246:        std::unique_ptr<VirtIOThread> backend /*{}*/;
                    247: 
                    248:        InterruptDevice *interrupt {};
                    249:        MainbusDevice *mainbus {};
1.1.1.2   root      250:        MainRAMDevice *mainram {};
                    251: 
1.1.1.3   root      252:        Monitor *monitor {};
1.1       root      253: };
                    254: 
                    255: // VirtIO 空きスロット用
                    256: class VirtIONoneDevice : public IODevice
                    257: {
                    258:        using inherited = IODevice;
                    259:  public:
                    260:        VirtIONoneDevice();
                    261:        ~VirtIONoneDevice() override;
                    262: 
1.1.1.2   root      263:  protected:
                    264:        // BusIO インタフェース
                    265:        static const uint32 NPORT = 0x200 >> 2;
                    266:        busdata ReadPort(uint32 offset);
                    267:        busdata WritePort(uint32 offset, uint32 data);
                    268:        busdata PeekPort(uint32 offset);
1.1       root      269: };
                    270: 
                    271: // 裏スレッド
                    272: class VirtIOThread : public ThreadDevice
                    273: {
                    274:        using inherited = ThreadDevice;
                    275: 
                    276:  protected:
                    277:        // REQ_QUEUE はキュー1本に1ビットずつ割り当てているので現状最大31まで。
                    278:        static const uint32 REQ_TERMINATE       = 0x80000000;   // スレッド終了指示
1.1.1.2   root      279:        static constexpr uint32 REQ_QUEUE(uint idx) {           // QUEUE_NOTIFY 指示
1.1       root      280:                return (1U << idx);
                    281:        }
                    282: 
                    283:  public:
1.1.1.2   root      284:        explicit VirtIOThread(VirtIODevice *parent_);
1.1       root      285:        ~VirtIOThread() override;
                    286: 
                    287:        void Terminate() override;
                    288: 
                    289:        // ゲストからの QUEUE_NOTIFY 要求
1.1.1.2   root      290:        void RequestQueueNotify(uint);
1.1       root      291: 
                    292:  private:
                    293:        void ThreadRun() override;
                    294: 
                    295:  protected:
                    296:        // リクエストフラグ
                    297:        uint32 request {};
                    298:        std::mutex mtx {};
                    299:        std::condition_variable cv {};
                    300: 
                    301:        VirtIODevice *parent {};
                    302: };

unix.superglobalmegacorp.com

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