|
|
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: {
1.1.1.5 root 38: try {
39: backend.reset(new VirtIOThread(this));
40: } catch (...) { }
1.1 root 41: if ((bool)backend == false) {
1.1.1.5 root 42: warnx("Failed to initialize VirtIOThread at %s", __method__);
1.1 root 43: return false;
44: }
45:
46: return true;
47: }
48:
49: // ログレベルを設定。
50: void
51: VirtIODevice::SetLogLevel(int loglevel_)
52: {
53: inherited::SetLogLevel(loglevel_);
54:
1.1.1.5 root 55: if ((bool)backend) {
56: backend->SetLogLevel(loglevel_);
57: }
1.1 root 58: }
59:
60: // 初期化
61: bool
62: VirtIODevice::Init()
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: // 先頭のインデックス。
601: idx = ReadLE16(q->driver + 4 + q->Mod(q->last_avail_idx) * 2);
1.1.1.5 root 602: if ((int32)idx < 0) {
1.1.1.2 root 603: return;
604: }
605: req.idx = idx;
606:
607: do {
608: // desc[idx] を読み出す。
609: uint32 descaddr = q->desc + idx * 16;
610: uint32 addr;
611: uint32 slen;
612: addr = ReadLE32(descaddr + 0);
613: slen = ReadLE32(descaddr + 8);
614: flag = ReadLE16(descaddr + 12);
615: idx = ReadLE16(descaddr + 14); // Next Index
616:
617: if ((flag & VIRTQ_DESC_F_INDIRECT)) {
618: AddIndirectDesc(req, addr, slen);
619: } else {
1.1.1.5 root 620: if ((flag & VIRTQ_DESC_F_WRITE)) {
621: putlog(3, "req.wbuf[%u]: addr=$%08x len=$%04x",
622: (uint)req.wbuf.size(), addr, slen);
623: req.wbuf.emplace_back(addr, slen);
624: req.wlen += slen;
625: } else {
626: putlog(3, "req.rbuf[%u]: addr=$%08x len=$%04x",
627: (uint)req.rbuf.size(), addr, slen);
628: req.rbuf.emplace_back(addr, slen);
629: req.rlen += slen;
630: }
1.1.1.2 root 631: }
632: } while ((flag & VIRTQ_DESC_F_NEXT));
633: }
634:
635: // 間接ディスクリプタを追加する。
636: void
637: VirtIODevice::AddIndirectDesc(VirtIOReq& req, uint32 table, uint32 tablelen)
638: {
639: uint32 count = tablelen / 16;
640: uint32 flag;
641: uint32 idx;
642:
643: idx = 0;
644: do {
645: if (__predict_false(idx >= count)) {
646: // 指定されたテーブル領域外を指していたらどうする?
647: putlog(0, "Invalid indirect table index=%u (count=%u)",
648: idx, count);
649: return;
650: }
651: uint32 descaddr = table + idx * 16;
652: uint32 addr;
653: uint32 slen;
654: addr = ReadLE32(descaddr + 0);
655: slen = ReadLE32(descaddr + 8);
656: flag = ReadLE16(descaddr + 12);
657: idx = ReadLE16(descaddr + 14);
658:
1.1.1.5 root 659: if ((flag & VIRTQ_DESC_F_WRITE)) {
660: putlog(3, "req.wbuf[%u]: addr=$%08x len=$%04x (Indirect)",
661: (uint)req.wbuf.size(), addr, slen);
662: req.wbuf.emplace_back(addr, slen);
663: req.wlen += slen;
664: } else {
665: putlog(3, "req.rbuf[%u]: addr=$%08x len=$%04x (Indirect)",
666: (uint)req.rbuf.size(), addr, slen);
667: req.rbuf.emplace_back(addr, slen);
668: req.rlen += slen;
669: }
1.1.1.2 root 670: } while ((flag & VIRTQ_DESC_F_NEXT));
671: }
672:
1.1 root 673: // ディスクリプタ処理完了。
674: void
1.1.1.2 root 675: VirtIODevice::CommitDesc(VirtIOReq& req)
1.1 root 676: {
1.1.1.2 root 677: VirtQueue *q = req.q;
678:
1.1 root 679: // Used Ring に記録。
680: uint16 used_idx = ReadLE16(q->device + 2);
1.1.1.2 root 681: WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 0, req.idx);
1.1.1.5 root 682: WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 4, req.pos());
1.1 root 683: used_idx++;
684: WriteLE16(q->device + 2, used_idx);
685:
686: // 最後に自身の last_avail_idx を更新。
687: q->last_avail_idx = (uint16)(q->last_avail_idx + 1);
688: }
689:
1.1.1.2 root 690: // この req から1バイト読み込む。
691: // 読み込めなければ -1 を返す。
692: uint32
693: VirtIODevice::ReqReadU8(VirtIOReq& req)
694: {
1.1.1.5 root 695: if (req.reof()) {
1.1.1.2 root 696: return -1;
697: }
1.1.1.5 root 698: assert(req.roff < req.rbuf[req.rseg].len);
699:
700: uint32 data = ReadU8(req.rbuf[req.rseg].addr + req.roff);
701: req.roff++;
702: if (req.roff >= req.rbuf[req.rseg].len) {
703: req.rseg++;
704: req.roff = 0;
1.1.1.2 root 705: }
706: return data;
707: }
708:
709: // この req から LE16 を読み込む。
710: // 読み込めなければ -1 を返す。
711: uint32
712: VirtIODevice::ReqReadLE16(VirtIOReq& req)
713: {
714: uint32 hi, lo;
715:
716: lo = ReqReadU8(req);
717: if ((int32)lo < 0) {
718: return lo;
719: }
720: hi = ReqReadU8(req);
721: if ((int32)hi < 0) {
722: return hi;
723: }
724:
725: return lo | (hi << 8);
726: }
727:
728: // この req から LE32 を読み込む。
729: // 読み込めなければ -1 を返す。
730: uint64
731: VirtIODevice::ReqReadLE32(VirtIOReq& req)
732: {
733: uint32 hi, lo;
734:
735: lo = ReqReadLE16(req);
736: if ((int32)lo < 0) {
737: return lo;
738: }
739: hi = ReqReadLE16(req);
740: if ((int32)hi < 0) {
741: return hi;
742: }
743:
744: return lo | (hi << 16);
745: }
746:
747: // この req から LE32 を読み込んで *retp に格納する。
748: // 読み込めなければ false を返す。
749: bool
750: VirtIODevice::ReqReadLE32(VirtIOReq& req, uint32 *retp)
751: {
752: uint64 val = ReqReadLE32(req);
753: if ((int64)val < 0) {
754: return false;
755: }
756:
757: *retp = (uint32)val;
758: return true;
759: }
760:
761: // この req から LE64 を読み込んで *retp に格納する。
762: // 読み込めなければ false を返す。
763: bool
764: VirtIODevice::ReqReadLE64(VirtIOReq& req, uint64 *retp)
765: {
766: uint64 hi, lo;
767:
768: lo = ReqReadLE32(req);
769: if ((int64)lo < 0) {
770: return false;
771: }
772: hi = ReqReadLE32(req);
773: if ((int64)hi < 0) {
774: return false;
775: }
776:
777: *retp = lo | (hi << 32);
778: return true;
779: }
780:
781: // この req に1バイト書き出す。
782: bool
783: VirtIODevice::ReqWriteU8(VirtIOReq& req, uint32 data)
784: {
1.1.1.5 root 785: if (req.weof()) {
1.1.1.2 root 786: return false;
787: }
1.1.1.5 root 788: assert(req.woff < req.wbuf[req.wseg].len);
1.1.1.2 root 789:
1.1.1.5 root 790: WriteU8(req.wbuf[req.wseg].addr + req.woff, data);
791: req.woff++;
792: if (req.woff >= req.wbuf[req.wseg].len) {
793: req.wseg++;
794: req.woff = 0;
1.1.1.2 root 795: }
796: return true;
797: }
798:
1.1.1.5 root 799: // この req に LE16 を書き出す。
800: bool
801: VirtIODevice::ReqWriteLE16(VirtIOReq& req, uint32 data)
802: {
803: if (ReqWriteU8(req, data & 0xff) == false) {
804: return false;
805: }
806: if (ReqWriteU8(req, (data >> 8)) == false) {
807: return false;
808: }
809: return true;
810: }
811:
812: // この req に LE32 を書き出す。
813: bool
814: VirtIODevice::ReqWriteLE32(VirtIOReq& req, uint32 data)
815: {
816: if (ReqWriteLE16(req, data & 0xffff) == false) {
817: return false;
818: }
819: if (ReqWriteLE16(req, (data >> 16)) == false) {
820: return false;
821: }
822: return true;
823: }
824:
825: // この req から dst に dstlen バイト読み込む。
826: // dstlen のうち読み込めなかったバイト数を返す (すべて読み込めたら 0 を返す)。
827: uint32
828: VirtIODevice::ReqReadRegion(VirtIOReq& req, uint8 *dst, uint32 dstlen)
829: {
830: uint8 *d = dst;
831:
832: while (dstlen != 0) {
833: if (req.reof()) {
834: break;
835: }
836:
837: // 今回読み込むバイト数と読み出し元 VM アドレス。
838: uint32 len = std::min(req.rbuf[req.rseg].len - req.roff, dstlen);
839: uint32 addr = req.rbuf[req.rseg].addr + req.roff;
840: // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。
841: // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない)
842: // mainbus 経由でアクセスする。
843: bool ok = mainram->ReadMem(addr, d, len);
844: if (__predict_true(ok)) {
845: d += len;
846: } else {
847: for (uint32 end = addr + len; addr < end; ) {
848: *d++ = ReadU8(addr++);
849: }
850: }
851: // この加算でセグメント長を超えることはない。
852: req.roff += len;
853: if (req.roff == req.rbuf[req.rseg].len) {
854: req.rseg++;
855: req.roff = 0;
856: }
857: dstlen -= len;
858: }
859:
860: return dstlen;
861: }
862:
863: // src から req に srclen バイト書き出す。
864: // srclen のうち書き出せなかったバイト数を返す (すべて書き出せたら 0 を返す)。
865: uint32
866: VirtIODevice::ReqWriteRegion(VirtIOReq& req, const uint8 *src, uint32 srclen)
867: {
868: const uint8 *s = src;
869:
870: while (srclen != 0) {
871: if (req.weof()) {
872: break;
873: }
874:
875: // 今回書き出すバイト数と書き込み先 VM アドレス。
876: uint32 len = std::min(req.wbuf[req.wseg].len - req.woff, srclen);
877: uint32 addr = req.wbuf[req.wseg].addr + req.woff;
878: // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。
879: // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない)
880: // mainbus 経由でアクセスする。
881: bool ok = mainram->WriteMem(addr, s, len);
882: if (__predict_true(ok)) {
883: s += len;
884: } else {
885: for (uint32 end = addr + len; addr < end; ) {
886: WriteU8(addr++, *s);
887: }
888: }
889: // この加算でセグメント長を超えることはない。
890: req.woff += len;
891: if (req.woff == req.wbuf[req.wseg].len) {
892: req.wseg++;
893: req.woff = 0;
894: }
895: srclen -= len;
896: }
897:
898: return srclen;
899: }
900:
1.1 root 901: // 裏スレッドからの処理完了メッセージ通知。(VM スレッドで実行される)
902: // arg はキュー番号。
903: void
904: VirtIODevice::DoneMessage(MessageID msgid_, uint32 arg)
905: {
906: int idx = arg;
907: VirtQueue *q = &vqueues[idx];
908:
909: Done(q);
910: }
911:
912: // ディスクリプタ処理が完了したので、必要なら割り込みを上げる。
913: // (VM スレッドで呼ぶこと)
914: void
915: VirtIODevice::Done(VirtQueue *q)
916: {
917: // (必要なら) 割り込みを上げる。
918: uint16 flag = ReadLE16(q->driver + 0);
919: if ((flag & VIRTQ_AVAIL_F_NO_INTERRUPT) == 0) {
920: intr_status |= 0x01;
921: ChangeInterrupt();
922: }
923: }
924:
925: // 割り込み信号線の状態を変える。
926: void
927: VirtIODevice::ChangeInterrupt()
928: {
929: assert(interrupt);
930: interrupt->ChangeINT(this, (bool)intr_status);
931: }
932:
933: // メインバスから U8 を読み込む。
934: uint32
935: VirtIODevice::ReadU8(uint32 addr)
936: {
1.1.1.2 root 937: busdata data = mainbus->HVRead1(addr);
1.1 root 938: return (uint8)data.Data();
939: }
940:
941: // メインバスから LE16 を読み込む。
942: uint32
943: VirtIODevice::ReadLE16(uint32 addr)
944: {
1.1.1.2 root 945: busdata data = mainbus->HVRead2(addr);
1.1 root 946: return be16toh(data.Data());
947: }
948:
949: // メインバスから LE32 を読み込む。
950: uint32
951: VirtIODevice::ReadLE32(uint32 addr)
952: {
1.1.1.2 root 953: busdata data = mainbus->HVRead4(addr);
1.1 root 954: return be32toh(data.Data());
955: }
956:
957: // メインバスから LE64 を読み込む。
958: uint64
959: VirtIODevice::ReadLE64(uint32 addr)
960: {
961: uint64 data;
962: data = (uint64)ReadLE32(addr + 0);
963: data |= (uint64)ReadLE32(addr + 4) << 32;
964:
965: return data;
966: }
967:
968: // メインバスに U8 を書き出す。
969: void
970: VirtIODevice::WriteU8(uint32 addr, uint32 data)
971: {
1.1.1.2 root 972: mainbus->HVWrite1(addr, data);
1.1 root 973: }
974:
975: // メインバスに LE16 を書き出す。
976: void
977: VirtIODevice::WriteLE16(uint32 addr, uint32 data)
978: {
1.1.1.2 root 979: mainbus->HVWrite2(addr, htobe16(data));
1.1 root 980: }
981:
982: // メインバスに LE32 を書き出す。
983: void
984: VirtIODevice::WriteLE32(uint32 addr, uint32 data)
985: {
1.1.1.2 root 986: mainbus->HVWrite4(addr, htobe32(data));
1.1 root 987: }
988:
989: // メインバスに LE64 を書き出す。
990: void
991: VirtIODevice::WriteLE64(uint32 addr, uint64 data)
992: {
993: WriteLE32(addr + 0, data & 0xffffffff);
994: WriteLE32(addr + 4, data >> 32);
995: }
996:
997: // メインバスから副作用なく LE16 を読み出す。
998: uint32
999: VirtIODevice::PeekLE16(uint32 addr) const
1000: {
1001: uint32 data;
1.1.1.2 root 1002: data = mainbus->Peek1(addr + 0);
1003: data |= mainbus->Peek1(addr + 1) << 8;
1.1 root 1004: return data;
1005: }
1006:
1007: // メインバスから副作用なく LE32 を読み出す。
1008: uint32
1009: VirtIODevice::PeekLE32(uint32 addr) const
1010: {
1011: uint32 data;
1.1.1.2 root 1012: data = mainbus->Peek1(addr + 0);
1013: data |= mainbus->Peek1(addr + 1) << 8;
1014: data |= mainbus->Peek1(addr + 2) << 16;
1015: data |= mainbus->Peek1(addr + 3) << 24;
1.1 root 1016: return data;
1017: }
1018:
1019: // DEVICE_FEATURES にビットを立てる。初期化用。
1020: void
1021: VirtIODevice::SetDeviceFeatures(int feature)
1022: {
1.1.1.2 root 1023: uint sel = feature / 32;
1024: uint bit = feature % 32;
1.1 root 1025: assert(sel < MAX_FEATURES_SEL);
1026: device_features[sel] |= (1U << bit);
1027: }
1028:
1029: // DRIVER_FEATURES のビットが立っていれば true を返す。
1030: bool
1031: VirtIODevice::GetDriverFeatures(int feature) const
1032: {
1.1.1.2 root 1033: uint sel = feature / 32;
1034: uint bit = feature % 32;
1.1 root 1035: assert(sel < MAX_FEATURES_SEL);
1036: return (driver_features[sel] & (1U << bit));
1037: }
1038:
1039: // FEATURES 名を返す。(共通部分)
1040: const char *
1.1.1.2 root 1041: VirtIODevice::GetFeatureName(uint feature) const
1.1 root 1042: {
1043: static std::pair<uint, const char *> names[] = {
1.1.1.2 root 1044: { VIRTIO_F_RING_INDIRECT_DESC, "INDIRECT" },
1.1 root 1045: { VIRTIO_F_RING_EVENT_IDX, "RING_EVENT" },
1046: { VIRTIO_F_VERSION_1, "VER1" },
1047: { VIRTIO_F_ACCESS_PLATFORM, "ACCESS_PLATFORM" },
1048: { VIRTIO_F_RING_PACKED, "RING_PACK" },
1049: { VIRTIO_F_IN_ORDER, "IN_ORDER" },
1050: { VIRTIO_F_ORDER_PLATFORM, "ORDER_PLATFORM" },
1051: { VIRTIO_F_SF_IOV, "SF_IOV" },
1052: { VIRTIO_F_NOTIFICATION_DATA, "NOTIFICATION_DATA" },
1053: };
1054:
1055: for (auto& p : names) {
1056: if (feature == p.first) {
1057: return p.second;
1058: }
1059: }
1060: return NULL;
1061: }
1062:
1063:
1064: //
1065: // VirtIONone (空きスロット用)
1066: //
1067:
1068: // コンストラクタ
1069: VirtIONoneDevice::VirtIONoneDevice()
1070: : inherited(OBJ_NONE)
1071: {
1.1.1.6 ! root 1072: SetName("VirtIONone");
1.1 root 1073: }
1074:
1075: // デストラクタ
1076: VirtIONoneDevice::~VirtIONoneDevice()
1077: {
1078: }
1079:
1080: busdata
1.1.1.2 root 1081: VirtIONoneDevice::ReadPort(uint32 offset)
1.1 root 1082: {
1.1.1.2 root 1083: busdata data = PeekPort(offset);
1.1 root 1084:
1.1.1.2 root 1085: if (__predict_false(loglevel >= 1)) {
1086: uint32 addr = offset << 2;
1087: switch (addr) {
1088: case VirtIO::MAGIC_VALUE:
1089: putlogn("MAGIC_VALUE -> $%08x", data.Data());
1090: break;
1.1 root 1091:
1.1.1.2 root 1092: case VirtIO::DEVICE_ID:
1093: putlogn("DEVICE_ID -> $%08x", data.Data());
1094: break;
1.1 root 1095:
1.1.1.2 root 1096: default:
1097: putlogn("REG%03x -> $%08x", addr, data.Data());
1098: break;
1099: }
1.1 root 1100: }
1.1.1.2 root 1101:
1102: data |= BusData::Size4;
1.1 root 1103: return data;
1104: }
1105:
1106: busdata
1.1.1.2 root 1107: VirtIONoneDevice::WritePort(uint32 offset, uint32 data)
1.1 root 1108: {
1.1.1.2 root 1109: return BusData::BusErr;
1.1 root 1110: }
1111:
1112: busdata
1.1.1.2 root 1113: VirtIONoneDevice::PeekPort(uint32 offset)
1.1 root 1114: {
1.1.1.2 root 1115: uint32 addr = offset << 2;
1.1 root 1116:
1.1.1.2 root 1117: switch (addr) {
1.1 root 1118: case VirtIO::MAGIC_VALUE:
1.1.1.2 root 1119: return VirtIO::MAGIC_STRING;
1120:
1.1 root 1121: case VirtIO::DEVICE_ID:
1.1.1.2 root 1122: return VirtIO::DEVICE_ID_INVALID;
1.1 root 1123:
1124: default:
1.1.1.2 root 1125: return 0xffffffff;
1.1 root 1126: }
1127: }
1128:
1129:
1130: //
1131: // VirtIOThread
1132: //
1133:
1134: // コンストラクタ
1135: VirtIOThread::VirtIOThread(VirtIODevice *parent_)
1136: : inherited(OBJ_NONE)
1137: {
1138: parent = parent_;
1139: SetName(parent->GetName());
1.1.1.5 root 1140:
1141: // コンストラクト後ただちにログ出力できるようここで一度追従しておく。
1142: // 以降は親クラス(表スレッド)の SetLogLevel() で変更する。
1143: loglevel = parent->loglevel;
1.1 root 1144: }
1145:
1146: // デストラクタ
1147: VirtIOThread::~VirtIOThread()
1148: {
1149: TerminateThread();
1150: }
1151:
1152: // 本当は ResetHard() で処理中のものをとめたほうがいいんだろうけど。
1153:
1154: // スレッドの終了を指示
1155: void
1156: VirtIOThread::Terminate()
1157: {
1.1.1.6 ! root 1158: std::lock_guard<std::mutex> lock(mtx);
1.1 root 1159: request |= REQ_TERMINATE;
1160: cv.notify_one();
1161: }
1162:
1163: // ゲストからの QUEUE_NOTIFY 要求。(VM スレッドで呼ばれる)
1164: void
1.1.1.2 root 1165: VirtIOThread::RequestQueueNotify(uint idx)
1.1 root 1166: {
1.1.1.6 ! root 1167: std::lock_guard<std::mutex> lock(mtx);
1.1 root 1168: request |= REQ_QUEUE(idx);
1169: cv.notify_one();
1170: }
1171:
1172: // スレッド
1173: void
1174: VirtIOThread::ThreadRun()
1175: {
1.1.1.2 root 1176: // どっちだろうか
1177: SetThreadAffinityHint(AffinityClass::Light);
1178:
1.1 root 1179: for (;;) {
1180: uint32 req;
1181:
1182: // 何か起きるまで待つ。
1183: {
1184: std::unique_lock<std::mutex> lock(mtx);
1185: cv.wait(lock, [&] { return (request != 0); });
1186: req = request;
1187: request = 0;
1188: }
1189:
1190: if ((req & REQ_TERMINATE)) {
1191: // 終了するので、他のフラグは無視。
1192: break;
1193: }
1194:
1195: // idx 番目のキューに QUEUE_NOTIFY が指示された。
1196: for (; req != 0; ) {
1197: int idx = __builtin_ctz(req);
1198: // 裏スレッドで Device クラスの関数を実行する。ややこしいので注意。
1199: parent->QueueNotify(idx);
1200: req &= ~(1U << idx);
1201: }
1202: }
1203: }
1204:
1205:
1206: //
1207: // VirtQueue
1208: //
1209:
1210: // コンストラクタ
1.1.1.3 root 1211: VirtQueue::VirtQueue(VirtIODevice *parent_, int idx_, const std::string& name_,
1212: int num_max_)
1.1 root 1213: {
1.1.1.3 root 1214: parent = parent_;
1.1 root 1215: idx = idx_;
1216: name = name_;
1217: num_max = num_max_;
1218: }
1.1.1.3 root 1219:
1220: // QUEUE_READY の代入。
1221: void
1222: VirtQueue::SetReady(uint32 val)
1223: {
1224: if (val != ready) {
1225: ready = val;
1226: parent->QueueReadyChanged(this);
1227: }
1228: }
1.1.1.5 root 1229:
1230:
1231: //
1232: // VirtIOReq
1233: //
1234:
1235: // 読み込みセグメントの先頭からの現在位置を返す。
1236: uint32
1237: VirtIOReq::rpos() const
1238: {
1239: uint32 totalpos = 0;
1240:
1241: for (int i = 0; i < rseg; i++) {
1242: totalpos += rbuf[i].len;
1243: }
1244: if (rseg < rbuf.size()) {
1245: totalpos += roff;
1246: }
1247: return totalpos;
1248: }
1249:
1250: // 書き込みセグメントの先頭からの現在位置を返す。
1251: uint32
1252: VirtIOReq::wpos() const
1253: {
1254: uint32 totalpos = 0;
1255:
1256: for (int i = 0; i < wseg; i++) {
1257: totalpos += wbuf[i].len;
1258: }
1259: if (wseg < wbuf.size()) {
1260: totalpos += woff;
1261: }
1262: return totalpos;
1263: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.