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