|
|
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.