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

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

unix.superglobalmegacorp.com

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