|
|
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: #include "virtio_base.h"
12: #include "goldfish_pic.h"
13: #include "virtio_def.h"
14: #include "mainbus.h"
1.1.1.2 root 15: #include "mainram.h"
1.1 root 16: #include "scheduler.h"
17:
18: //
19: // VirtIO 基本クラス
20: //
21:
22: // コンストラクタ
1.1.1.2 root 23: VirtIODevice::VirtIODevice(uint objid_, uint slot_)
1.1 root 24: : inherited(objid_)
25: {
26: slot = slot_;
27: }
28:
29: // デストラクタ
30: VirtIODevice::~VirtIODevice()
31: {
32: }
33:
34: // 動的なコンストラクション
35: bool
36: VirtIODevice::Create()
37: {
38: backend.reset(new VirtIOThread(this));
39: if ((bool)backend == false) {
40: return false;
41: }
42:
43: return true;
44: }
45:
46: // ログレベルを設定。
47: void
48: VirtIODevice::SetLogLevel(int loglevel_)
49: {
50: inherited::SetLogLevel(loglevel_);
51:
52: // バックエンドにも伝達。
53: backend->SetLogLevel(loglevel_);
54: }
55:
56: // 初期化
57: bool
58: VirtIODevice::Init()
59: {
60: mainbus = GetMainbusDevice();
1.1.1.2 root 61: mainram = GetMainRAMDevice();
1.1 root 62:
63: // GFPIC に割り込みを登録する。
64: // 継承側のコンストラクタで intrname の設定をしておくこと。
65: assert(intrname[0]);
1.1.1.2 root 66: uint pic = (slot / 32) + 2;
67: uint irq = (slot % 32) + 1;
1.1 root 68: auto gfpic = GetGFPICDevice(pic);
69: gfpic->RegistIRQ(irq, intrname, this);
70:
71: interrupt = gfpic;
72:
73: // DEVICE_FEATURES (共通部) を用意。
1.1.1.2 root 74: SetDeviceFeatures(VIRTIO_F_RING_INDIRECT_DESC);
1.1 root 75: SetDeviceFeatures(VIRTIO_F_VERSION_1);
76:
77: // 裏スレッドからの DONE コールバックを登録。
78: assert(msgid != 0);
79: scheduler->ConnectMessage(msgid, this,
80: ToMessageCallback(&VirtIODevice::DoneMessage));
81:
82: return true;
83: }
84:
85: // リセット
86: void
87: VirtIODevice::ResetHard(bool poweron)
88: {
1.1.1.2 root 89: Reset();
1.1 root 90: }
91:
1.1.1.2 root 92: // BusIO のオフセットはこのポート幅で先頭から 0個目、1個目と数えるが、
93: // VirtIO の仕様でレジスタは $00、$04 のようにアドレスで数えるので
94: // オフセットで渡されたものをもう一回アドレスに戻す…。
95:
1.1 root 96: // レジスタ部 (<0x100) はゲストエンディアン (BE)
97: // コンフィグ部 (>=0x100) はリトルエンディアン。
98:
99: busdata
1.1.1.2 root 100: VirtIODevice::ReadPort(uint32 offset)
1.1 root 101: {
1.1.1.2 root 102: busdata data;
1.1 root 103:
1.1.1.2 root 104: data = PeekPort(offset);
1.1 root 105:
1.1.1.2 root 106: if (__predict_false(loglevel >= 2)) {
107: uint32 addr = offset << 2;
108: if (addr < 0x100) {
109: switch (addr) {
1.1 root 110: case VirtIO::MAGIC_VALUE:
1.1.1.2 root 111: putlogn("MAGIC_VALUE -> $%08x", data.Data());
1.1 root 112: break;
113: case VirtIO::VERSION:
1.1.1.2 root 114: putlogn("VERSION -> $%08x", data.Data());
1.1 root 115: break;
116: case VirtIO::DEVICE_ID:
1.1.1.2 root 117: putlogn("DEVICE_ID -> $%08x", data.Data());
1.1 root 118: break;
119: case VirtIO::VENDOR_ID:
1.1.1.2 root 120: putlogn("VENDOR_ID -> $%08x", data.Data());
1.1 root 121: break;
122: case VirtIO::DEVICE_FEATURES:
1.1.1.2 root 123: putlogn("DEVICE_FEATURES[%x] -> $%08x",
124: device_sel, data.Data());
1.1 root 125: break;
126: case VirtIO::STATUS:
1.1.1.2 root 127: putlogn("STATUS -> $%08x%s", data.Data(),
1.1 root 128: VirtIO::StatusBits(data).c_str());
129: break;
130: case VirtIO::QUEUE_NUM_MAX:
1.1.1.2 root 131: putlogn("QUEUE_NUM_MAX(%u) -> $%08x", queue_sel, data.Data());
1.1 root 132: break;
133: case VirtIO::INTERRUPT_STATUS:
1.1.1.2 root 134: putlogn("INTERRUPT_STATUS -> $%08x", data.Data());
1.1 root 135: break;
136: default:
1.1.1.2 root 137: putlogn("REG%03x -> $%08x", addr, data.Data());
1.1 root 138: break;
139: }
1.1.1.2 root 140: } else {
141: putlogn("CONFIG:%03x -> $%08x", addr, data.Data());
1.1 root 142: }
143: }
144:
1.1.1.2 root 145: data |= BusData::Size4;
146: return data;
1.1 root 147: }
148:
149: busdata
1.1.1.2 root 150: VirtIODevice::WritePort(uint32 offset, uint32 data)
1.1 root 151: {
1.1.1.2 root 152: busdata r = BusData::Size4;
1.1 root 153:
1.1.1.2 root 154: uint32 addr = offset << 2;
155: if (addr >= 0x100) {
156: putlog(1, "Write $%03x (Not writeable)", addr);
157: return r;
1.1 root 158: }
159:
1.1.1.2 root 160: switch (addr) {
1.1 root 161: case VirtIO::STATUS:
162: // 0 を書き込むとデバイスリセット。
163: // 0 以外はステータスの書き込み。
164: device_status = data;
165: putlog(2, "STATUS <- $%08x%s", device_status,
166: VirtIO::StatusBits(device_status).c_str());
1.1.1.2 root 167: if (device_status == 0) {
168: Reset();
169: }
1.1 root 170: break;
171:
172: case VirtIO::DEVICE_FEATURES_SEL:
173: device_sel = data;
174: if (device_sel >= MAX_FEATURES_SEL) {
175: putlog(1, "DEVICE_FEATURES_SEL <- $%08x (out of range!)",
176: device_sel);
177: } else {
178: putlog(2, "DEVICE_FEATURES_SEL <- $%08x", device_sel);
179: }
180: break;
181:
182: case VirtIO::DRIVER_FEATURES:
183: if (driver_sel >= MAX_FEATURES_SEL) {
184: putlog(1, "DRIVER_FEATURES[%x] <- $%08x (!)", driver_sel, data);
185: } else {
186: driver_features[driver_sel] = data;
187: putlog(2, "DRIVER_FEATURES[%x] <- $%08x", driver_sel, data);
188: }
189: break;
190:
191: case VirtIO::DRIVER_FEATURES_SEL:
192: driver_sel = data;
193: if (driver_sel >= MAX_FEATURES_SEL) {
194: putlog(1, "DRIVER_FEATURES_SEL <- $%08x (out of range!)",
195: driver_sel);
196: } else {
197: putlog(2, "DRIVER_FEATURES_SEL <- $%08x", driver_sel);
198: }
199: break;
200:
201: case VirtIO::QUEUE_SEL:
202: queue_sel = data;
203: if (vqueues.empty() && queue_sel == 0) {
204: vq = NULL;
205: putlog(3, "QUEUE_SEL <- $%08x", queue_sel);
206: } else if (queue_sel < vqueues.size()) {
207: vq = &vqueues[queue_sel];
208: putlog(3, "QUEUE_SEL <- $%08x", queue_sel);
209: } else {
210: putlog(1, "QUEUE_SEL <- $%08x (out of range!)", queue_sel);
211: }
212: break;
213:
214: case VirtIO::QUEUE_NUM:
215: putlog(2, "QUEUE_NUM(%u) <- $%08x", queue_sel, data);
216: if (vq) {
217: if (data > vq->num_max) {
218: data = vq->num_max;
219: putlog(1, "QUEUE_NUM(%u) = $%08x", queue_sel, data);
220: }
221: vq->num = data;
222: }
223: break;
224:
225: case VirtIO::QUEUE_READY:
226: putlog(2, "QUEUE_READY(%u) <- $%08x", queue_sel, data);
227: if (vq) {
1.1.1.3 root 228: vq->SetReady(data);
1.1 root 229: }
230: break;
231:
232: case VirtIO::QUEUE_NOTIFY:
233: putlog(2, "QUEUE_NOTIFY(%u) <- $%08x", queue_sel, data);
234: if (vq) {
235: backend->RequestQueueNotify(vq->idx);
236: }
237: break;
238:
239: case VirtIO::INTERRUPT_ACK:
240: intr_status &= ~data;
241: putlog(2, "INTERRUPT_ACK <- $%08x (STATUS = $%08x)", data, intr_status);
242: ChangeInterrupt();
243: break;
244:
245: case VirtIO::QUEUE_DESC_LOW:
246: putlog(2, "QUEUE_DESC_LOW(%u) <- $%08x", queue_sel, data);
247: if (vq) {
248: vq->desc = data;
249: }
250: break;
251: case VirtIO::QUEUE_DESC_HIGH:
252: putlog((vq == NULL || data != 0) ? 1 : 3,
253: "QUEUE_DESC_HIGH(%u) <- $%08x", queue_sel, data);
254: break;
255:
256: case VirtIO::QUEUE_DRIVER_LOW:
257: putlog(2, "QUEUE_DRIVER_LOW(%u) <- $%08x", queue_sel, data);
258: if (vq) {
259: vq->driver = data;
260: }
261: break;
262: case VirtIO::QUEUE_DRIVER_HIGH:
263: putlog((vq == NULL || data != 0) ? 1 : 3,
264: "QUEUE_DRIVER_HIGH(%u) <- $%08x", queue_sel, data);
265: break;
266:
267: case VirtIO::QUEUE_DEVICE_LOW:
268: putlog(2, "QUEUE_DEVICE_LOW(%u) <- $%08x", queue_sel, data);
269: if (vq) {
270: vq->device = data;
271: }
272: break;
273: case VirtIO::QUEUE_DEVICE_HIGH:
274: putlog((vq == NULL || data != 0) ? 1 : 3,
275: "QUEUE_DEVICE_HIGH(%u) <- $%08x", queue_sel, data);
276: break;
277:
278: default:
1.1.1.2 root 279: putlog(0, "Write $%03x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1 root 280: break;
281: }
282:
1.1.1.2 root 283: return r;
1.1 root 284: }
285:
286: busdata
1.1.1.2 root 287: VirtIODevice::PeekPort(uint32 offset)
1.1 root 288: {
1.1.1.2 root 289: uint32 data;
1.1 root 290:
1.1.1.2 root 291: uint32 addr = offset << 2;
1.1 root 292:
1.1.1.2 root 293: if (addr < 0x100) {
294: data = GetReg(addr);
1.1 root 295: } else {
296: // コンフィグ部はバイトイメージなのでそのまま。
1.1.1.2 root 297: addr -= 0x100;
298: data = (device_config[addr + 0] << 24)
299: | (device_config[addr + 1] << 16)
300: | (device_config[addr + 2] << 8)
301: | (device_config[addr + 3]);
1.1 root 302: }
1.1.1.2 root 303:
304: return busdata(data);
1.1 root 305: }
306:
307: // 下請け、デバイス情報部分。
308: int
309: VirtIODevice::MonitorUpdateDev(TextScreen& screen, int y) const
310: {
311: // 0 1 2 3 4 5 6 7
312: // 012345678901234567890123456789012345678901234567890123456789012345678901234
313: // DeviceType: 2(Block Device) DeviceAddr: $00000000 (Slot $00)
314:
1.1.1.2 root 315: screen.Print(0, y, "DeviceType: %u(%s)",
1.1 root 316: device_id, VirtIO::DeviceIDStr(device_id).c_str());
317: screen.Print(43, y, "DeviceAddr: $%08x (Slot $%02x)",
318: baseaddr + slot * 0x200, slot);
319: y++;
320:
321: // Features
322: // XXX まだ折り返しは考慮してない。
323: uint64 features = ((uint64)device_features[1] << 32) | device_features[0];
324: screen.Puts(0, y, "Features:");
325: int x = 12;
326: for (int f = 63; f >= 0; f--) {
327: if ((features & (1ULL << f)) == 0)
328: continue;
329: bool enabled = GetDriverFeatures(f);
330: const char *name = GetFeatureName(f);
331: if (__predict_true(name)) {
332: screen.Puts(x, y, TA::OnOff(enabled), name);
333: x += strlen(name) + 1;
334: } else {
335: std::string buf = string_format("(%u)", f);
336: screen.Puts(x, y, TA::OnOff(enabled), buf.c_str());
337: x += buf.size() + 1;
338: }
339: }
340: y++;
341:
342: return y;
343: }
344:
345: // 下請け、VirtQueue 1本の概要。
346: int
347: VirtIODevice::MonitorUpdateVirtQueue(TextScreen& screen, int y,
348: const VirtQueue& q) const
349: {
350: // 0 1 2 3 4 5 6 7
351: // 012345678901234567890123456789012345678901234567890123456789012345678901234
352: // VirtQueue0 "TransmitQ1" (NUM=4/128)
353: // TableAddr: Desc=$00000000 Avail=$00000000(NoIntr) Used=$00000000(NoNotify)
354: // Ring: LastAvail=$0000 Avail=$0000 (Head=$0000) Used=$0000
355:
1.1.1.2 root 356: screen.Print(0, y++, "VirtQueue%u: \"%s\" (NUM=%u/%u)",
1.1 root 357: q.idx, q.name.c_str(), q.num, q.num_max);
358:
359: screen.Puts(1, y, "TableAddr:");
360: if (__predict_true(q.desc != 0xcccccccc)) {
361: screen.Print(12, y, "Desc=$%08x", q.desc);
362: }
363: if (__predict_true(q.driver != 0xcccccccc)) {
364: uint16 flag = PeekLE16(q.driver + 0);
365: screen.Print(27, y, "Avail=$%08x(", q.driver);
366: screen.Puts(43, y, TA::OnOff(flag & VIRTQ_AVAIL_F_NO_INTERRUPT),
367: "NoIntr");
368: screen.Putc(49, y, ')');
369: }
370: if (__predict_true(q.device != 0xcccccccc)) {
371: uint16 flag = PeekLE16(q.device + 0);
372: screen.Print(51, y, "Used=$%08x(", q.device);
373: screen.Puts(66, y, TA::OnOff(flag & VIRTQ_USED_F_NO_NOTIFY),
374: "NoNotify");
375: screen.Putc(74, y, ')');
376: }
377: y++;
378:
379: screen.Puts(1, y, "Ring:");
1.1.1.3 root 380: if (__predict_true(q.GetReady())) {
1.1 root 381: uint16 aidx = PeekLE16(q.driver + 2);
1.1.1.2 root 382: uint16 head = PeekLE16(q.driver + 4 + q.Mod(aidx) * 2);
1.1 root 383: uint16 uidx = PeekLE16(q.device + 2);
384:
385: screen.Print(12, y, "LastAvail=$%04x", q.last_avail_idx);
386: screen.Print(29, y, "Avail=$%04x (Head=$%04x)", aidx, head);
387: screen.Print(55, y, "Used=$%04x", uidx);
388: }
389: y++;
390:
391: return y;
392: }
393:
394: // 下請け、VirtQDesc テーブル。(デバッグ用)
395: int
396: VirtIODevice::MonitorUpdateVirtQDesc(TextScreen& screen, int y,
397: const VirtQueue& q) const
398: {
399: int x0;
400: int x1;
401: int x2;
402:
403: // 0 1 2 3 4 5 6 7
404: // 01234567890123456789012345678901234567890123456789012345678901234567890
405: // Descriptor AvailRing UsedRing
406: // No Address Length Flags Next ID ID Len
407: // 00 $00000000 00000000 0001(IRN) 0000 G> 0000 <H 00000000 00112233 <H
408: // 01 $00000000 00000000 0001(IRN) 0000 0000 00000000 00000000
409: // 02 $00000000 00000000 0001(IRN) 0000 0000 00000000 00000000
410: // 03 $00000000 00000000 0001(IRN) 0000 0000 00000000 00000000
411:
412: x0 = 1;
413: x1 = 42;
414: x2 = 51;
415:
416: screen.Puts(x0, y, "Descriptor");
417: screen.Puts(x1 - 3, y, "AvailRing");
418: screen.Puts(x2, y, "UsedRing");
419: y++;
420: screen.Puts(x0, y, "No Address Length Flags Next");
421: screen.Puts(x1, y, "ID");
422: screen.Puts(x2, y, "ID Length");
423: y++;
424:
425: int ytop = y;
426: int i;
1.1.1.2 root 427: for (i = 0; i < q.num; i++) {
1.1 root 428: // Desc Table
429: uint32 desc = q.desc + i * 16;
430: uint32 addr = PeekLE32(desc + 0x00);
431: uint32 len = PeekLE32(desc + 0x08);
432: uint32 flag = PeekLE16(desc + 0x0c);
433: uint32 next = PeekLE16(desc + 0x0e);
434: screen.Print(x0, y, "%02x $%08x %08x %04x(%c%c%c) %04x",
435: i, addr, len, flag,
436: ((flag & VIRTQ_DESC_F_INDIRECT) ? 'I' : '-'),
437: ((flag & VIRTQ_DESC_F_WRITE) ? 'W' : 'R'),
438: ((flag & VIRTQ_DESC_F_NEXT) ? 'N' : '-'),
439: next);
440:
441: // Avail Ring
442: uint16 a_ring = PeekLE16(q.driver + 4 + i * 2);
443: screen.Print(x1, y, "%04x", a_ring);
444:
445: // Used Ring
446: uint32 u_id = PeekLE32(q.device + 4 + i * 8 + 0);
447: uint32 u_len = PeekLE32(q.device + 4 + i * 8 + 4);
448: screen.Print(x2, y, "%08x %08x", u_id, u_len);
449:
450: y++;
451: }
452: for (; i < q.num_max; i++) {
453: screen.Print(x0, y++, TA::Disable, "%02x", i);
454: }
455:
1.1.1.3 root 456: if (__predict_true(q.GetReady())) {
1.1 root 457: uint avail_idx = PeekLE16(q.driver + 2);
458: uint used_idx = PeekLE16(q.device + 2);
1.1.1.2 root 459: screen.Puts(x1 - 3, ytop + q.Mod(avail_idx), "G>");
460: screen.Puts(x1 + 5, ytop + q.Mod(q.last_avail_idx), "<H");
461: screen.Puts(x2 + 18, ytop + q.Mod(used_idx), "<H");
1.1 root 462: }
463:
464: return y;
465: }
466:
1.1.1.2 root 467: // デバイスをリセット。
468: void
469: VirtIODevice::Reset()
470: {
471: device_status = VirtIO::STATUS_RESET;
472: device_sel = 0;
473: driver_sel = 0;
474:
475: for (int i = 0; i < MAX_FEATURES_SEL; i++) {
476: driver_features[i] = 0;
477: }
478:
479: for (int i = 0; i < vqueues.size(); i++) {
480: auto& q = vqueues[i];
481: q.idx = i;
482: // モニタの見栄えのため未設定時は無効値を入れておく
483: q.desc = 0xcccccccc;
484: q.driver = 0xcccccccc;
485: q.device = 0xcccccccc;
486: q.num = 0;
1.1.1.3 root 487: q.SetReady(0);
1.1.1.2 root 488: q.last_avail_idx = 0;
489: }
490: vq = NULL;
491:
492: intr_status = 0;
493: ChangeInterrupt();
494: }
495:
1.1 root 496: // レジスタ部の値を返す。
497: uint32
1.1.1.2 root 498: VirtIODevice::GetReg(uint32 addr) const
1.1 root 499: {
1.1.1.2 root 500: switch (addr) {
1.1 root 501: case VirtIO::MAGIC_VALUE:
502: return VirtIO::MAGIC_STRING;
503:
504: case VirtIO::VERSION:
505: return VirtIO::DEVICE_VERSION;
506:
507: case VirtIO::DEVICE_ID:
508: return device_id;
509:
510: case VirtIO::VENDOR_ID:
511: return vendor_id;
512:
513: case VirtIO::DEVICE_FEATURES:
514: if (device_sel >= MAX_FEATURES_SEL) {
515: return 0;
516: }
517: return device_features[device_sel];
518:
519: case VirtIO::STATUS:
520: return device_status;
521:
522: case VirtIO::QUEUE_NUM_MAX:
523: if (vq) {
524: return vq->num_max;
525: } else {
526: return 0;
527: }
528:
529: case VirtIO::QUEUE_READY:
530: if (vq) {
1.1.1.3 root 531: return vq->GetReady();
1.1 root 532: } else {
533: return 0;
534: }
535:
536: case VirtIO::INTERRUPT_STATUS:
537: return intr_status;
538:
539: case VirtIO::CONFIG_GENERATION:
540: return 0;
541:
542: default:
543: return 0xffffffff;
544: }
545: }
546:
1.1.1.3 root 547: // QUEUE_READY が更新された時に呼ばれる。必要ならオーバーライドする。
548: // q->ready が 0 なら Not ready(初期状態)、1 なら Ready。
1.1 root 549: void
1.1.1.3 root 550: VirtIODevice::QueueReadyChanged(VirtQueue *q)
1.1 root 551: {
552: }
553:
554: // QUEUE_NOTIFY の処理。(これは裏スレッドで実行される)
555: void
1.1.1.2 root 556: VirtIODevice::QueueNotify(uint idx)
1.1 root 557: {
1.1.1.2 root 558: assert(idx < vqueues.size());
1.1 root 559: VirtQueue *q = &vqueues[idx];
560:
561: // avail_idx に追いつくまで処理。
562: for (;;) {
563: uint16 avail_idx = ReadLE16(q->driver + 2);
564: putlog(3, "last_avail_idx=$%04x avail_idx=$%04x",
565: q->last_avail_idx, avail_idx);
566: if (q->last_avail_idx == avail_idx) {
567: break;
568: }
569:
1.1.1.2 root 570: // last_avail_idx の指すディスクリプタを読み出す。
571: VirtIOReq req;
572: req.q = q;
573: StartDesc(req);
574:
575: // デバイス固有の処理。
576: ProcessDesc(req);
577:
578: // 完了
579: CommitDesc(req);
1.1 root 580:
581: // VM スレッドに完了通知。
582: scheduler->SendMessage(msgid, q->idx);
583: }
584: }
585:
1.1.1.2 root 586: // q->last_avail_idx の指すディスクリプタからの
587: // ディスクリプタチェイン req を構成する。
588: // req は初期化後 .q のみ代入した状態で呼ぶこと。
589: void
590: VirtIODevice::StartDesc(VirtIOReq& req)
591: {
592: const VirtQueue *q = req.q;
593: uint32 flag;
594: uint32 idx;
595:
596: req.pos = 0;
597: req.len = 0;
598:
599: // 先頭のインデックス。
600: idx = ReadLE16(q->driver + 4 + q->Mod(q->last_avail_idx) * 2);
601: if ((int32)idx<0) {
602: return;
603: }
604: req.idx = idx;
605:
606: do {
607: // desc[idx] を読み出す。
608: uint32 descaddr = q->desc + idx * 16;
609: uint32 addr;
610: uint32 slen;
611: addr = ReadLE32(descaddr + 0);
612: slen = ReadLE32(descaddr + 8);
613: flag = ReadLE16(descaddr + 12);
614: idx = ReadLE16(descaddr + 14); // Next Index
615:
616: if ((flag & VIRTQ_DESC_F_INDIRECT)) {
617: AddIndirectDesc(req, addr, slen);
618: } else {
619: // R/W 属性は無視する。
620: putlog(3, "req.buf[%u]: addr=$%08x off=$%08x len=$%04x",
621: (uint)req.buf.size(), addr, req.len, slen);
622: req.buf.emplace_back(addr, req.len, slen);
623:
624: // セグメントオフセットを記録した後で足す。
625: req.len += slen;
626: }
627: } while ((flag & VIRTQ_DESC_F_NEXT));
628: }
629:
630: // 間接ディスクリプタを追加する。
631: void
632: VirtIODevice::AddIndirectDesc(VirtIOReq& req, uint32 table, uint32 tablelen)
633: {
634: uint32 count = tablelen / 16;
635: uint32 flag;
636: uint32 idx;
637:
638: idx = 0;
639: do {
640: if (__predict_false(idx >= count)) {
641: // 指定されたテーブル領域外を指していたらどうする?
642: putlog(0, "Invalid indirect table index=%u (count=%u)",
643: idx, count);
644: return;
645: }
646: uint32 descaddr = table + idx * 16;
647: uint32 addr;
648: uint32 slen;
649: addr = ReadLE32(descaddr + 0);
650: slen = ReadLE32(descaddr + 8);
651: flag = ReadLE16(descaddr + 12);
652: idx = ReadLE16(descaddr + 14);
653:
654: putlog(3, "req.buf[%u]: addr=$%08x off=$%08x len=$%04x (Indirect)",
655: (uint)req.buf.size(), addr, req.len, slen);
656:
657: req.buf.emplace_back(addr, req.len, slen);
658:
659: // セグメントオフセットを記録した後で足す。
660: req.len += slen;
661: } while ((flag & VIRTQ_DESC_F_NEXT));
662: }
663:
1.1 root 664: // ディスクリプタ処理完了。
665: void
1.1.1.2 root 666: VirtIODevice::CommitDesc(VirtIOReq& req)
1.1 root 667: {
1.1.1.2 root 668: VirtQueue *q = req.q;
669:
1.1 root 670: // Used Ring に記録。
671: uint16 used_idx = ReadLE16(q->device + 2);
1.1.1.2 root 672: WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 0, req.idx);
673: WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 4, req.pos);
1.1 root 674: used_idx++;
675: WriteLE16(q->device + 2, used_idx);
676:
677: // 最後に自身の last_avail_idx を更新。
678: q->last_avail_idx = (uint16)(q->last_avail_idx + 1);
679: }
680:
1.1.1.2 root 681: // この req から1バイト読み込む。
682: // 読み込めなければ -1 を返す。
683: uint32
684: VirtIODevice::ReqReadU8(VirtIOReq& req)
685: {
686: if (req.pos >= req.len) {
687: return -1;
688: }
689: auto seg = req.buf[req.curseg];
690: int segoff = req.pos - seg.pos;
691: uint8 data = ReadU8(seg.addr + segoff);
692:
693: req.pos++;
694: if (++segoff >= seg.len) {
695: req.curseg++;
696: }
697: return data;
698: }
699:
700: // この req から LE16 を読み込む。
701: // 読み込めなければ -1 を返す。
702: uint32
703: VirtIODevice::ReqReadLE16(VirtIOReq& req)
704: {
705: uint32 hi, lo;
706:
707: lo = ReqReadU8(req);
708: if ((int32)lo < 0) {
709: return lo;
710: }
711: hi = ReqReadU8(req);
712: if ((int32)hi < 0) {
713: return hi;
714: }
715:
716: return lo | (hi << 8);
717: }
718:
719: // この req から LE32 を読み込む。
720: // 読み込めなければ -1 を返す。
721: uint64
722: VirtIODevice::ReqReadLE32(VirtIOReq& req)
723: {
724: uint32 hi, lo;
725:
726: lo = ReqReadLE16(req);
727: if ((int32)lo < 0) {
728: return lo;
729: }
730: hi = ReqReadLE16(req);
731: if ((int32)hi < 0) {
732: return hi;
733: }
734:
735: return lo | (hi << 16);
736: }
737:
738: // この req から LE32 を読み込んで *retp に格納する。
739: // 読み込めなければ false を返す。
740: bool
741: VirtIODevice::ReqReadLE32(VirtIOReq& req, uint32 *retp)
742: {
743: uint64 val = ReqReadLE32(req);
744: if ((int64)val < 0) {
745: return false;
746: }
747:
748: *retp = (uint32)val;
749: return true;
750: }
751:
752: // この req から LE64 を読み込んで *retp に格納する。
753: // 読み込めなければ false を返す。
754: bool
755: VirtIODevice::ReqReadLE64(VirtIOReq& req, uint64 *retp)
756: {
757: uint64 hi, lo;
758:
759: lo = ReqReadLE32(req);
760: if ((int64)lo < 0) {
761: return false;
762: }
763: hi = ReqReadLE32(req);
764: if ((int64)hi < 0) {
765: return false;
766: }
767:
768: *retp = lo | (hi << 32);
769: return true;
770: }
771:
772: // この req に1バイト書き出す。
773: bool
774: VirtIODevice::ReqWriteU8(VirtIOReq& req, uint32 data)
775: {
776: if (req.pos >= req.len) {
777: return false;
778: }
779:
780: const auto seg = req.buf[req.curseg];
781: int segoff = req.pos - seg.pos;
782: WriteU8(seg.addr + segoff, data);
783:
784: req.pos++;
785: if (++segoff >= seg.len) {
786: req.curseg++;
787: }
788: return true;
789: }
790:
1.1 root 791: // 裏スレッドからの処理完了メッセージ通知。(VM スレッドで実行される)
792: // arg はキュー番号。
793: void
794: VirtIODevice::DoneMessage(MessageID msgid_, uint32 arg)
795: {
796: int idx = arg;
797: VirtQueue *q = &vqueues[idx];
798:
799: Done(q);
800: }
801:
802: // ディスクリプタ処理が完了したので、必要なら割り込みを上げる。
803: // (VM スレッドで呼ぶこと)
804: void
805: VirtIODevice::Done(VirtQueue *q)
806: {
807: // (必要なら) 割り込みを上げる。
808: uint16 flag = ReadLE16(q->driver + 0);
809: if ((flag & VIRTQ_AVAIL_F_NO_INTERRUPT) == 0) {
810: intr_status |= 0x01;
811: ChangeInterrupt();
812: }
813: }
814:
815: // 割り込み信号線の状態を変える。
816: void
817: VirtIODevice::ChangeInterrupt()
818: {
819: assert(interrupt);
820: interrupt->ChangeINT(this, (bool)intr_status);
821: }
822:
823: // メインバスから U8 を読み込む。
824: uint32
825: VirtIODevice::ReadU8(uint32 addr)
826: {
1.1.1.2 root 827: busdata data = mainbus->HVRead1(addr);
1.1 root 828: return (uint8)data.Data();
829: }
830:
831: // メインバスから LE16 を読み込む。
832: uint32
833: VirtIODevice::ReadLE16(uint32 addr)
834: {
1.1.1.2 root 835: busdata data = mainbus->HVRead2(addr);
1.1 root 836: return be16toh(data.Data());
837: }
838:
839: // メインバスから LE32 を読み込む。
840: uint32
841: VirtIODevice::ReadLE32(uint32 addr)
842: {
1.1.1.2 root 843: busdata data = mainbus->HVRead4(addr);
1.1 root 844: return be32toh(data.Data());
845: }
846:
847: // メインバスから LE64 を読み込む。
848: uint64
849: VirtIODevice::ReadLE64(uint32 addr)
850: {
851: uint64 data;
852: data = (uint64)ReadLE32(addr + 0);
853: data |= (uint64)ReadLE32(addr + 4) << 32;
854:
855: return data;
856: }
857:
858: // メインバスに U8 を書き出す。
859: void
860: VirtIODevice::WriteU8(uint32 addr, uint32 data)
861: {
1.1.1.2 root 862: mainbus->HVWrite1(addr, data);
1.1 root 863: }
864:
865: // メインバスに LE16 を書き出す。
866: void
867: VirtIODevice::WriteLE16(uint32 addr, uint32 data)
868: {
1.1.1.2 root 869: mainbus->HVWrite2(addr, htobe16(data));
1.1 root 870: }
871:
872: // メインバスに LE32 を書き出す。
873: void
874: VirtIODevice::WriteLE32(uint32 addr, uint32 data)
875: {
1.1.1.2 root 876: mainbus->HVWrite4(addr, htobe32(data));
1.1 root 877: }
878:
879: // メインバスに LE64 を書き出す。
880: void
881: VirtIODevice::WriteLE64(uint32 addr, uint64 data)
882: {
883: WriteLE32(addr + 0, data & 0xffffffff);
884: WriteLE32(addr + 4, data >> 32);
885: }
886:
887: // メインバスから副作用なく LE16 を読み出す。
888: uint32
889: VirtIODevice::PeekLE16(uint32 addr) const
890: {
891: uint32 data;
1.1.1.2 root 892: data = mainbus->Peek1(addr + 0);
893: data |= mainbus->Peek1(addr + 1) << 8;
1.1 root 894: return data;
895: }
896:
897: // メインバスから副作用なく LE32 を読み出す。
898: uint32
899: VirtIODevice::PeekLE32(uint32 addr) const
900: {
901: uint32 data;
1.1.1.2 root 902: data = mainbus->Peek1(addr + 0);
903: data |= mainbus->Peek1(addr + 1) << 8;
904: data |= mainbus->Peek1(addr + 2) << 16;
905: data |= mainbus->Peek1(addr + 3) << 24;
1.1 root 906: return data;
907: }
908:
909: // DEVICE_FEATURES にビットを立てる。初期化用。
910: void
911: VirtIODevice::SetDeviceFeatures(int feature)
912: {
1.1.1.2 root 913: uint sel = feature / 32;
914: uint bit = feature % 32;
1.1 root 915: assert(sel < MAX_FEATURES_SEL);
916: device_features[sel] |= (1U << bit);
917: }
918:
919: // DRIVER_FEATURES のビットが立っていれば true を返す。
920: bool
921: VirtIODevice::GetDriverFeatures(int feature) const
922: {
1.1.1.2 root 923: uint sel = feature / 32;
924: uint bit = feature % 32;
1.1 root 925: assert(sel < MAX_FEATURES_SEL);
926: return (driver_features[sel] & (1U << bit));
927: }
928:
929: // FEATURES 名を返す。(共通部分)
930: const char *
1.1.1.2 root 931: VirtIODevice::GetFeatureName(uint feature) const
1.1 root 932: {
933: static std::pair<uint, const char *> names[] = {
1.1.1.2 root 934: { VIRTIO_F_RING_INDIRECT_DESC, "INDIRECT" },
1.1 root 935: { VIRTIO_F_RING_EVENT_IDX, "RING_EVENT" },
936: { VIRTIO_F_VERSION_1, "VER1" },
937: { VIRTIO_F_ACCESS_PLATFORM, "ACCESS_PLATFORM" },
938: { VIRTIO_F_RING_PACKED, "RING_PACK" },
939: { VIRTIO_F_IN_ORDER, "IN_ORDER" },
940: { VIRTIO_F_ORDER_PLATFORM, "ORDER_PLATFORM" },
941: { VIRTIO_F_SF_IOV, "SF_IOV" },
942: { VIRTIO_F_NOTIFICATION_DATA, "NOTIFICATION_DATA" },
943: };
944:
945: for (auto& p : names) {
946: if (feature == p.first) {
947: return p.second;
948: }
949: }
950: return NULL;
951: }
952:
953:
954: //
955: // VirtIONone (空きスロット用)
956: //
957:
958: // コンストラクタ
959: VirtIONoneDevice::VirtIONoneDevice()
960: : inherited(OBJ_NONE)
961: {
962: }
963:
964: // デストラクタ
965: VirtIONoneDevice::~VirtIONoneDevice()
966: {
967: }
968:
969: busdata
1.1.1.2 root 970: VirtIONoneDevice::ReadPort(uint32 offset)
1.1 root 971: {
1.1.1.2 root 972: busdata data = PeekPort(offset);
1.1 root 973:
1.1.1.2 root 974: if (__predict_false(loglevel >= 1)) {
975: uint32 addr = offset << 2;
976: switch (addr) {
977: case VirtIO::MAGIC_VALUE:
978: putlogn("MAGIC_VALUE -> $%08x", data.Data());
979: break;
1.1 root 980:
1.1.1.2 root 981: case VirtIO::DEVICE_ID:
982: putlogn("DEVICE_ID -> $%08x", data.Data());
983: break;
1.1 root 984:
1.1.1.2 root 985: default:
986: putlogn("REG%03x -> $%08x", addr, data.Data());
987: break;
988: }
1.1 root 989: }
1.1.1.2 root 990:
991: data |= BusData::Size4;
1.1 root 992: return data;
993: }
994:
995: busdata
1.1.1.2 root 996: VirtIONoneDevice::WritePort(uint32 offset, uint32 data)
1.1 root 997: {
1.1.1.2 root 998: return BusData::BusErr;
1.1 root 999: }
1000:
1001: busdata
1.1.1.2 root 1002: VirtIONoneDevice::PeekPort(uint32 offset)
1.1 root 1003: {
1.1.1.2 root 1004: uint32 addr = offset << 2;
1.1 root 1005:
1.1.1.2 root 1006: switch (addr) {
1.1 root 1007: case VirtIO::MAGIC_VALUE:
1.1.1.2 root 1008: return VirtIO::MAGIC_STRING;
1009:
1.1 root 1010: case VirtIO::DEVICE_ID:
1.1.1.2 root 1011: return VirtIO::DEVICE_ID_INVALID;
1.1 root 1012:
1013: default:
1.1.1.2 root 1014: return 0xffffffff;
1.1 root 1015: }
1016: }
1017:
1018:
1019: //
1020: // VirtIOThread
1021: //
1022:
1023: // コンストラクタ
1024: VirtIOThread::VirtIOThread(VirtIODevice *parent_)
1025: : inherited(OBJ_NONE)
1026: {
1027: parent = parent_;
1028: SetName(parent->GetName());
1029: }
1030:
1031: // デストラクタ
1032: VirtIOThread::~VirtIOThread()
1033: {
1034: TerminateThread();
1035: }
1036:
1037: // 本当は ResetHard() で処理中のものをとめたほうがいいんだろうけど。
1038:
1039: // スレッドの終了を指示
1040: void
1041: VirtIOThread::Terminate()
1042: {
1043: std::unique_lock<std::mutex> lock(mtx);
1044: request |= REQ_TERMINATE;
1045: cv.notify_one();
1046: }
1047:
1048: // ゲストからの QUEUE_NOTIFY 要求。(VM スレッドで呼ばれる)
1049: void
1.1.1.2 root 1050: VirtIOThread::RequestQueueNotify(uint idx)
1.1 root 1051: {
1052: std::unique_lock<std::mutex> lock(mtx);
1053: request |= REQ_QUEUE(idx);
1054: cv.notify_one();
1055: }
1056:
1057: // スレッド
1058: void
1059: VirtIOThread::ThreadRun()
1060: {
1.1.1.2 root 1061: // どっちだろうか
1062: SetThreadAffinityHint(AffinityClass::Light);
1063:
1.1 root 1064: for (;;) {
1065: uint32 req;
1066:
1067: // 何か起きるまで待つ。
1068: {
1069: std::unique_lock<std::mutex> lock(mtx);
1070: cv.wait(lock, [&] { return (request != 0); });
1071: req = request;
1072: request = 0;
1073: }
1074:
1075: if ((req & REQ_TERMINATE)) {
1076: // 終了するので、他のフラグは無視。
1077: break;
1078: }
1079:
1080: // idx 番目のキューに QUEUE_NOTIFY が指示された。
1081: for (; req != 0; ) {
1082: int idx = __builtin_ctz(req);
1083: // 裏スレッドで Device クラスの関数を実行する。ややこしいので注意。
1084: parent->QueueNotify(idx);
1085: req &= ~(1U << idx);
1086: }
1087: }
1088: }
1089:
1090:
1091: //
1092: // VirtQueue
1093: //
1094:
1095: // コンストラクタ
1.1.1.3 root 1096: VirtQueue::VirtQueue(VirtIODevice *parent_, int idx_, const std::string& name_,
1097: int num_max_)
1.1 root 1098: {
1.1.1.3 root 1099: parent = parent_;
1.1 root 1100: idx = idx_;
1101: name = name_;
1102: num_max = num_max_;
1103: }
1.1.1.3 root 1104:
1105: // QUEUE_READY の代入。
1106: void
1107: VirtQueue::SetReady(uint32 val)
1108: {
1109: if (val != ready) {
1110: ready = val;
1111: parent->QueueReadyChanged(this);
1112: }
1113: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.