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