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