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

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

unix.superglobalmegacorp.com

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