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