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

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

unix.superglobalmegacorp.com

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