Annotation of nono/vm/virtio_base.cpp, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.