Annotation of nono/vm/virtio_base.cpp, revision 1.1.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.