|
|
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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.