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

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

unix.superglobalmegacorp.com

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