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