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

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: {
1.1.1.5   root       38:        try {
                     39:                backend.reset(new VirtIOThread(this));
                     40:        } catch (...) { }
1.1       root       41:        if ((bool)backend == false) {
1.1.1.5   root       42:                warnx("Failed to initialize VirtIOThread at %s", __method__);
1.1       root       43:                return false;
                     44:        }
                     45: 
                     46:        return true;
                     47: }
                     48: 
                     49: // ログレベルを設定。
                     50: void
                     51: VirtIODevice::SetLogLevel(int loglevel_)
                     52: {
                     53:        inherited::SetLogLevel(loglevel_);
                     54: 
1.1.1.5   root       55:        if ((bool)backend) {
                     56:                backend->SetLogLevel(loglevel_);
                     57:        }
1.1       root       58: }
                     59: 
                     60: // 初期化
                     61: bool
                     62: VirtIODevice::Init()
                     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) {
1.1.1.3   root      232:                        vq->SetReady(data);
1.1       root      233:                }
                    234:                break;
                    235: 
                    236:         case VirtIO::QUEUE_NOTIFY:
                    237:                putlog(2, "QUEUE_NOTIFY(%u) <- $%08x", queue_sel, data);
                    238:                if (vq) {
                    239:                        backend->RequestQueueNotify(vq->idx);
                    240:                }
                    241:                break;
                    242: 
                    243:         case VirtIO::INTERRUPT_ACK:
                    244:                intr_status &= ~data;
                    245:                putlog(2, "INTERRUPT_ACK <- $%08x (STATUS = $%08x)", data, intr_status);
                    246:                ChangeInterrupt();
                    247:                break;
                    248: 
                    249:         case VirtIO::QUEUE_DESC_LOW:
                    250:                putlog(2, "QUEUE_DESC_LOW(%u) <- $%08x", queue_sel, data);
                    251:                if (vq) {
                    252:                        vq->desc = data;
                    253:                }
                    254:                break;
                    255:         case VirtIO::QUEUE_DESC_HIGH:
                    256:                putlog((vq == NULL || data != 0) ? 1 : 3,
                    257:                        "QUEUE_DESC_HIGH(%u) <- $%08x", queue_sel, data);
                    258:                break;
                    259: 
                    260:         case VirtIO::QUEUE_DRIVER_LOW:
                    261:                putlog(2, "QUEUE_DRIVER_LOW(%u) <- $%08x", queue_sel, data);
                    262:                if (vq) {
                    263:                        vq->driver = data;
                    264:                }
                    265:                break;
                    266:         case VirtIO::QUEUE_DRIVER_HIGH:
                    267:                putlog((vq == NULL || data != 0) ? 1 : 3,
                    268:                        "QUEUE_DRIVER_HIGH(%u) <- $%08x", queue_sel, data);
                    269:                break;
                    270: 
                    271:         case VirtIO::QUEUE_DEVICE_LOW:
                    272:                putlog(2, "QUEUE_DEVICE_LOW(%u) <- $%08x", queue_sel, data);
                    273:                if (vq) {
                    274:                        vq->device = data;
                    275:                }
                    276:                break;
                    277:         case VirtIO::QUEUE_DEVICE_HIGH:
                    278:                putlog((vq == NULL || data != 0) ? 1 : 3,
                    279:                        "QUEUE_DEVICE_HIGH(%u) <- $%08x", queue_sel, data);
                    280:                break;
                    281: 
                    282:         default:
1.1.1.2   root      283:                putlog(0, "Write $%03x <- $%08x (NOT IMPLEMENTED)", addr, data);
1.1       root      284:                break;
                    285:        }
                    286: 
1.1.1.2   root      287:        return r;
1.1       root      288: }
                    289: 
                    290: busdata
1.1.1.2   root      291: VirtIODevice::PeekPort(uint32 offset)
1.1       root      292: {
1.1.1.2   root      293:        uint32 data;
1.1       root      294: 
1.1.1.2   root      295:        uint32 addr = offset << 2;
1.1       root      296: 
1.1.1.2   root      297:        if (addr < 0x100) {
                    298:                data = GetReg(addr);
1.1       root      299:        } else {
                    300:                // コンフィグ部はバイトイメージなのでそのまま。
1.1.1.2   root      301:                addr -= 0x100;
                    302:                data = (device_config[addr + 0] << 24)
                    303:                     | (device_config[addr + 1] << 16)
                    304:                     | (device_config[addr + 2] << 8)
                    305:                     | (device_config[addr + 3]);
1.1       root      306:        }
1.1.1.2   root      307: 
                    308:        return busdata(data);
1.1       root      309: }
                    310: 
                    311: // 下請け、デバイス情報部分。
                    312: int
1.1.1.7 ! root      313: VirtIODevice::MonitorScreenDev(TextScreen& screen, int y) const
1.1       root      314: {
                    315: // 0         1         2         3         4         5         6         7
                    316: // 012345678901234567890123456789012345678901234567890123456789012345678901234
                    317: // DeviceType: 2(Block Device)                DeviceAddr: $00000000 (Slot $00)
                    318: 
1.1.1.2   root      319:        screen.Print(0, y, "DeviceType: %u(%s)",
1.1       root      320:                device_id, VirtIO::DeviceIDStr(device_id).c_str());
                    321:        screen.Print(43, y, "DeviceAddr: $%08x (Slot $%02x)",
                    322:                baseaddr + slot * 0x200, slot);
                    323:        y++;
                    324: 
                    325:        // Features
                    326:        // XXX まだ折り返しは考慮してない。
                    327:        uint64 features = ((uint64)device_features[1] << 32) | device_features[0];
                    328:        screen.Puts(0, y, "Features:");
                    329:        int x = 12;
                    330:        for (int f = 63; f >= 0; f--) {
                    331:                if ((features & (1ULL << f)) == 0)
                    332:                        continue;
                    333:                bool enabled = GetDriverFeatures(f);
                    334:                const char *name = GetFeatureName(f);
                    335:                if (__predict_true(name)) {
                    336:                        screen.Puts(x, y, TA::OnOff(enabled), name);
                    337:                        x += strlen(name) + 1;
                    338:                } else {
                    339:                        std::string buf = string_format("(%u)", f);
                    340:                        screen.Puts(x, y, TA::OnOff(enabled), buf.c_str());
                    341:                        x += buf.size() + 1;
                    342:                }
                    343:        }
                    344:        y++;
                    345: 
                    346:        return y;
                    347: }
                    348: 
                    349: // 下請け、VirtQueue 1本の概要。
                    350: int
1.1.1.7 ! root      351: VirtIODevice::MonitorScreenVirtQueue(TextScreen& screen, int y,
1.1       root      352:        const VirtQueue& q) const
                    353: {
                    354: // 0         1         2         3         4         5         6         7
                    355: // 012345678901234567890123456789012345678901234567890123456789012345678901234
                    356: // VirtQueue0 "TransmitQ1" (NUM=4/128)
                    357: //  TableAddr: Desc=$00000000 Avail=$00000000(NoIntr) Used=$00000000(NoNotify)
                    358: //  Ring:      LastAvail=$0000  Avail=$0000 (Head=$0000)  Used=$0000
                    359: 
1.1.1.2   root      360:        screen.Print(0, y++, "VirtQueue%u: \"%s\" (NUM=%u/%u)",
1.1       root      361:                q.idx, q.name.c_str(), q.num, q.num_max);
                    362: 
                    363:        screen.Puts(1, y, "TableAddr:");
                    364:        if (__predict_true(q.desc != 0xcccccccc)) {
                    365:                screen.Print(12, y, "Desc=$%08x", q.desc);
                    366:        }
                    367:        if (__predict_true(q.driver != 0xcccccccc)) {
                    368:                uint16 flag = PeekLE16(q.driver + 0);
                    369:                screen.Print(27, y, "Avail=$%08x(", q.driver);
                    370:                screen.Puts(43, y, TA::OnOff(flag & VIRTQ_AVAIL_F_NO_INTERRUPT),
                    371:                        "NoIntr");
                    372:                screen.Putc(49, y, ')');
                    373:        }
                    374:        if (__predict_true(q.device != 0xcccccccc)) {
                    375:                uint16 flag = PeekLE16(q.device + 0);
                    376:                screen.Print(51, y, "Used=$%08x(", q.device);
                    377:                screen.Puts(66, y, TA::OnOff(flag & VIRTQ_USED_F_NO_NOTIFY),
                    378:                        "NoNotify");
                    379:                screen.Putc(74, y, ')');
                    380:        }
                    381:        y++;
                    382: 
                    383:        screen.Puts(1, y, "Ring:");
1.1.1.3   root      384:        if (__predict_true(q.GetReady())) {
1.1       root      385:                uint16 aidx = PeekLE16(q.driver + 2);
1.1.1.2   root      386:                uint16 head = PeekLE16(q.driver + 4 + q.Mod(aidx) * 2);
1.1       root      387:                uint16 uidx = PeekLE16(q.device + 2);
                    388: 
                    389:                screen.Print(12, y, "LastAvail=$%04x", q.last_avail_idx);
                    390:                screen.Print(29, y, "Avail=$%04x (Head=$%04x)", aidx, head);
                    391:                screen.Print(55, y, "Used=$%04x", uidx);
                    392:        }
                    393:        y++;
                    394: 
                    395:        return y;
                    396: }
                    397: 
                    398: // 下請け、VirtQDesc テーブル。(デバッグ用)
                    399: int
1.1.1.7 ! root      400: VirtIODevice::MonitorScreenVirtQDesc(TextScreen& screen, int y,
1.1       root      401:        const VirtQueue& q) const
                    402: {
                    403:        int x0;
                    404:        int x1;
                    405:        int x2;
                    406: 
                    407:        // 0         1         2         3         4         5         6         7
                    408:        // 01234567890123456789012345678901234567890123456789012345678901234567890
                    409:        //  Descriptor                            AvailRing   UsedRing
                    410:        //  No Address   Length   Flags     Next     ID       ID       Len
                    411:        //  00 $00000000 00000000 0001(IRN) 0000  G> 0000 <H  00000000 00112233 <H
                    412:        //  01 $00000000 00000000 0001(IRN) 0000     0000     00000000 00000000
                    413:        //  02 $00000000 00000000 0001(IRN) 0000     0000     00000000 00000000
                    414:        //  03 $00000000 00000000 0001(IRN) 0000     0000     00000000 00000000
                    415: 
                    416:        x0 = 1;
                    417:        x1 = 42;
                    418:        x2 = 51;
                    419: 
                    420:        screen.Puts(x0, y, "Descriptor");
                    421:        screen.Puts(x1 - 3, y, "AvailRing");
                    422:        screen.Puts(x2, y, "UsedRing");
                    423:        y++;
                    424:        screen.Puts(x0, y, "No Address   Length   Flags     Next");
                    425:        screen.Puts(x1, y, "ID");
                    426:        screen.Puts(x2, y, "ID       Length");
                    427:        y++;
                    428: 
                    429:        int ytop = y;
                    430:        int i;
1.1.1.2   root      431:        for (i = 0; i < q.num; i++) {
1.1       root      432:                // Desc Table
                    433:                uint32 desc = q.desc + i * 16;
                    434:                uint32 addr = PeekLE32(desc + 0x00);
                    435:                uint32 len  = PeekLE32(desc + 0x08);
                    436:                uint32 flag = PeekLE16(desc + 0x0c);
                    437:                uint32 next = PeekLE16(desc + 0x0e);
                    438:                screen.Print(x0, y, "%02x $%08x %08x %04x(%c%c%c) %04x",
                    439:                        i, addr, len, flag,
                    440:                        ((flag & VIRTQ_DESC_F_INDIRECT) ? 'I' : '-'),
                    441:                        ((flag & VIRTQ_DESC_F_WRITE) ? 'W' : 'R'),
                    442:                        ((flag & VIRTQ_DESC_F_NEXT)  ? 'N' : '-'),
                    443:                        next);
                    444: 
                    445:                // Avail Ring
                    446:                uint16 a_ring = PeekLE16(q.driver + 4 + i * 2);
                    447:                screen.Print(x1, y, "%04x", a_ring);
                    448: 
                    449:                // Used Ring
                    450:                uint32 u_id  = PeekLE32(q.device + 4 + i * 8 + 0);
                    451:                uint32 u_len = PeekLE32(q.device + 4 + i * 8 + 4);
                    452:                screen.Print(x2, y, "%08x %08x", u_id, u_len);
                    453: 
                    454:                y++;
                    455:        }
                    456:        for (; i < q.num_max; i++) {
                    457:                screen.Print(x0, y++, TA::Disable, "%02x", i);
                    458:        }
                    459: 
1.1.1.3   root      460:        if (__predict_true(q.GetReady())) {
1.1       root      461:                uint avail_idx = PeekLE16(q.driver + 2);
                    462:                uint used_idx  = PeekLE16(q.device + 2);
1.1.1.2   root      463:                screen.Puts(x1 -  3, ytop + q.Mod(avail_idx), "G>");
                    464:                screen.Puts(x1 +  5, ytop + q.Mod(q.last_avail_idx), "<H");
                    465:                screen.Puts(x2 + 18, ytop + q.Mod(used_idx), "<H");
1.1       root      466:        }
                    467: 
                    468:        return y;
                    469: }
                    470: 
1.1.1.2   root      471: // デバイスをリセット。
                    472: void
                    473: VirtIODevice::Reset()
                    474: {
                    475:        device_status = VirtIO::STATUS_RESET;
                    476:        device_sel = 0;
                    477:        driver_sel = 0;
                    478: 
                    479:        for (int i = 0; i < MAX_FEATURES_SEL; i++) {
                    480:                driver_features[i] = 0;
                    481:        }
                    482: 
                    483:        for (int i = 0; i < vqueues.size(); i++) {
                    484:                auto& q = vqueues[i];
                    485:                q.idx = i;
                    486:                // モニタの見栄えのため未設定時は無効値を入れておく
                    487:                q.desc   = 0xcccccccc;
                    488:                q.driver = 0xcccccccc;
                    489:                q.device = 0xcccccccc;
                    490:                q.num = 0;
1.1.1.3   root      491:                q.SetReady(0);
1.1.1.2   root      492:                q.last_avail_idx = 0;
                    493:        }
                    494:        vq = NULL;
                    495: 
                    496:        intr_status = 0;
                    497:        ChangeInterrupt();
                    498: }
                    499: 
1.1       root      500: // レジスタ部の値を返す。
                    501: uint32
1.1.1.2   root      502: VirtIODevice::GetReg(uint32 addr) const
1.1       root      503: {
1.1.1.2   root      504:        switch (addr) {
1.1       root      505:         case VirtIO::MAGIC_VALUE:
                    506:                return VirtIO::MAGIC_STRING;
                    507: 
                    508:         case VirtIO::VERSION:
                    509:                return VirtIO::DEVICE_VERSION;
                    510: 
                    511:         case VirtIO::DEVICE_ID:
                    512:                return device_id;
                    513: 
                    514:         case VirtIO::VENDOR_ID:
                    515:                return vendor_id;
                    516: 
                    517:         case VirtIO::DEVICE_FEATURES:
                    518:                if (device_sel >= MAX_FEATURES_SEL) {
                    519:                        return 0;
                    520:                }
                    521:                return device_features[device_sel];
                    522: 
                    523:         case VirtIO::STATUS:
                    524:                return device_status;
                    525: 
                    526:         case VirtIO::QUEUE_NUM_MAX:
                    527:                if (vq) {
                    528:                        return vq->num_max;
                    529:                } else {
                    530:                        return 0;
                    531:                }
                    532: 
                    533:         case VirtIO::QUEUE_READY:
                    534:                if (vq) {
1.1.1.3   root      535:                        return vq->GetReady();
1.1       root      536:                } else {
                    537:                        return 0;
                    538:                }
                    539: 
                    540:         case VirtIO::INTERRUPT_STATUS:
                    541:                return intr_status;
                    542: 
                    543:         case VirtIO::CONFIG_GENERATION:
                    544:                return 0;
                    545: 
                    546:         default:
                    547:                return 0xffffffff;
                    548:        }
                    549: }
                    550: 
1.1.1.3   root      551: // QUEUE_READY が更新された時に呼ばれる。必要ならオーバーライドする。
                    552: // q->ready が 0 なら Not ready(初期状態)、1 なら Ready。
1.1       root      553: void
1.1.1.3   root      554: VirtIODevice::QueueReadyChanged(VirtQueue *q)
1.1       root      555: {
                    556: }
                    557: 
                    558: // QUEUE_NOTIFY の処理。(これは裏スレッドで実行される)
                    559: void
1.1.1.2   root      560: VirtIODevice::QueueNotify(uint idx)
1.1       root      561: {
1.1.1.2   root      562:        assert(idx < vqueues.size());
1.1       root      563:        VirtQueue *q = &vqueues[idx];
                    564: 
                    565:        // avail_idx に追いつくまで処理。
                    566:        for (;;) {
                    567:                uint16 avail_idx = ReadLE16(q->driver + 2);
                    568:                putlog(3, "last_avail_idx=$%04x avail_idx=$%04x",
                    569:                        q->last_avail_idx, avail_idx);
                    570:                if (q->last_avail_idx == avail_idx) {
                    571:                        break;
                    572:                }
                    573: 
1.1.1.2   root      574:                // last_avail_idx の指すディスクリプタを読み出す。
                    575:                VirtIOReq req;
                    576:                req.q = q;
                    577:                StartDesc(req);
                    578: 
                    579:                // デバイス固有の処理。
                    580:                ProcessDesc(req);
                    581: 
                    582:                // 完了
                    583:                CommitDesc(req);
1.1       root      584: 
                    585:                // VM スレッドに完了通知。
                    586:                scheduler->SendMessage(msgid, q->idx);
                    587:        }
                    588: }
                    589: 
1.1.1.2   root      590: // q->last_avail_idx の指すディスクリプタからの
                    591: // ディスクリプタチェイン req を構成する。
                    592: // req は初期化後 .q のみ代入した状態で呼ぶこと。
                    593: void
                    594: VirtIODevice::StartDesc(VirtIOReq& req)
                    595: {
                    596:        const VirtQueue *q = req.q;
                    597:        uint32 flag;
                    598:        uint32 idx;
                    599: 
                    600:        // 先頭のインデックス。
                    601:        idx = ReadLE16(q->driver + 4 + q->Mod(q->last_avail_idx) * 2);
1.1.1.5   root      602:        if ((int32)idx < 0) {
1.1.1.2   root      603:                return;
                    604:        }
                    605:        req.idx = idx;
                    606: 
                    607:        do {
                    608:                // desc[idx] を読み出す。
                    609:                uint32 descaddr = q->desc + idx * 16;
                    610:                uint32 addr;
                    611:                uint32 slen;
                    612:                addr = ReadLE32(descaddr + 0);
                    613:                slen = ReadLE32(descaddr + 8);
                    614:                flag = ReadLE16(descaddr + 12);
                    615:                idx  = ReadLE16(descaddr + 14); // Next Index
                    616: 
                    617:                if ((flag & VIRTQ_DESC_F_INDIRECT)) {
                    618:                        AddIndirectDesc(req, addr, slen);
                    619:                } else {
1.1.1.5   root      620:                        if ((flag & VIRTQ_DESC_F_WRITE)) {
                    621:                                putlog(3, "req.wbuf[%u]: addr=$%08x len=$%04x",
                    622:                                        (uint)req.wbuf.size(), addr, slen);
                    623:                                req.wbuf.emplace_back(addr, slen);
                    624:                                req.wlen += slen;
                    625:                        } else {
                    626:                                putlog(3, "req.rbuf[%u]: addr=$%08x len=$%04x",
                    627:                                        (uint)req.rbuf.size(), addr, slen);
                    628:                                req.rbuf.emplace_back(addr, slen);
                    629:                                req.rlen += slen;
                    630:                        }
1.1.1.2   root      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: 
1.1.1.5   root      659:                if ((flag & VIRTQ_DESC_F_WRITE)) {
                    660:                        putlog(3, "req.wbuf[%u]: addr=$%08x len=$%04x (Indirect)",
                    661:                                (uint)req.wbuf.size(), addr, slen);
                    662:                        req.wbuf.emplace_back(addr, slen);
                    663:                        req.wlen += slen;
                    664:                } else {
                    665:                        putlog(3, "req.rbuf[%u]: addr=$%08x len=$%04x (Indirect)",
                    666:                                (uint)req.rbuf.size(), addr, slen);
                    667:                        req.rbuf.emplace_back(addr, slen);
                    668:                        req.rlen += slen;
                    669:                }
1.1.1.2   root      670:        } while ((flag & VIRTQ_DESC_F_NEXT));
                    671: }
                    672: 
1.1       root      673: // ディスクリプタ処理完了。
                    674: void
1.1.1.2   root      675: VirtIODevice::CommitDesc(VirtIOReq& req)
1.1       root      676: {
1.1.1.2   root      677:        VirtQueue *q = req.q;
                    678: 
1.1       root      679:        // Used Ring に記録。
                    680:        uint16 used_idx = ReadLE16(q->device + 2);
1.1.1.2   root      681:        WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 0, req.idx);
1.1.1.5   root      682:        WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 4, req.pos());
1.1       root      683:        used_idx++;
                    684:        WriteLE16(q->device + 2, used_idx);
                    685: 
                    686:        // 最後に自身の last_avail_idx を更新。
                    687:        q->last_avail_idx = (uint16)(q->last_avail_idx + 1);
                    688: }
                    689: 
1.1.1.2   root      690: // この req から1バイト読み込む。
                    691: // 読み込めなければ -1 を返す。
                    692: uint32
                    693: VirtIODevice::ReqReadU8(VirtIOReq& req)
                    694: {
1.1.1.5   root      695:        if (req.reof()) {
1.1.1.2   root      696:                return -1;
                    697:        }
1.1.1.5   root      698:        assert(req.roff < req.rbuf[req.rseg].len);
                    699: 
                    700:        uint32 data = ReadU8(req.rbuf[req.rseg].addr + req.roff);
                    701:        req.roff++;
                    702:        if (req.roff >= req.rbuf[req.rseg].len) {
                    703:                req.rseg++;
                    704:                req.roff = 0;
1.1.1.2   root      705:        }
                    706:        return data;
                    707: }
                    708: 
                    709: // この req から LE16 を読み込む。
                    710: // 読み込めなければ -1 を返す。
                    711: uint32
                    712: VirtIODevice::ReqReadLE16(VirtIOReq& req)
                    713: {
                    714:        uint32 hi, lo;
                    715: 
                    716:        lo = ReqReadU8(req);
                    717:        if ((int32)lo < 0) {
                    718:                return lo;
                    719:        }
                    720:        hi = ReqReadU8(req);
                    721:        if ((int32)hi < 0) {
                    722:                return hi;
                    723:        }
                    724: 
                    725:        return lo | (hi << 8);
                    726: }
                    727: 
                    728: // この req から LE32 を読み込む。
                    729: // 読み込めなければ -1 を返す。
                    730: uint64
                    731: VirtIODevice::ReqReadLE32(VirtIOReq& req)
                    732: {
                    733:        uint32 hi, lo;
                    734: 
                    735:        lo = ReqReadLE16(req);
                    736:        if ((int32)lo < 0) {
                    737:                return lo;
                    738:        }
                    739:        hi = ReqReadLE16(req);
                    740:        if ((int32)hi < 0) {
                    741:                return hi;
                    742:        }
                    743: 
                    744:        return lo | (hi << 16);
                    745: }
                    746: 
                    747: // この req から LE32 を読み込んで *retp に格納する。
                    748: // 読み込めなければ false を返す。
                    749: bool
                    750: VirtIODevice::ReqReadLE32(VirtIOReq& req, uint32 *retp)
                    751: {
                    752:        uint64 val = ReqReadLE32(req);
                    753:        if ((int64)val < 0) {
                    754:                return false;
                    755:        }
                    756: 
                    757:        *retp = (uint32)val;
                    758:        return true;
                    759: }
                    760: 
                    761: // この req から LE64 を読み込んで *retp に格納する。
                    762: // 読み込めなければ false を返す。
                    763: bool
                    764: VirtIODevice::ReqReadLE64(VirtIOReq& req, uint64 *retp)
                    765: {
                    766:        uint64 hi, lo;
                    767: 
                    768:        lo = ReqReadLE32(req);
                    769:        if ((int64)lo < 0) {
                    770:                return false;
                    771:        }
                    772:        hi = ReqReadLE32(req);
                    773:        if ((int64)hi < 0) {
                    774:                return false;
                    775:        }
                    776: 
                    777:        *retp = lo | (hi << 32);
                    778:        return true;
                    779: }
                    780: 
                    781: // この req に1バイト書き出す。
                    782: bool
                    783: VirtIODevice::ReqWriteU8(VirtIOReq& req, uint32 data)
                    784: {
1.1.1.5   root      785:        if (req.weof()) {
1.1.1.2   root      786:                return false;
                    787:        }
1.1.1.5   root      788:        assert(req.woff < req.wbuf[req.wseg].len);
1.1.1.2   root      789: 
1.1.1.5   root      790:        WriteU8(req.wbuf[req.wseg].addr + req.woff, data);
                    791:        req.woff++;
                    792:        if (req.woff >= req.wbuf[req.wseg].len) {
                    793:                req.wseg++;
                    794:                req.woff = 0;
1.1.1.2   root      795:        }
                    796:        return true;
                    797: }
                    798: 
1.1.1.5   root      799: // この req に LE16 を書き出す。
                    800: bool
                    801: VirtIODevice::ReqWriteLE16(VirtIOReq& req, uint32 data)
                    802: {
                    803:        if (ReqWriteU8(req, data & 0xff) == false) {
                    804:                return false;
                    805:        }
                    806:        if (ReqWriteU8(req, (data >> 8)) == false) {
                    807:                return false;
                    808:        }
                    809:        return true;
                    810: }
                    811: 
                    812: // この req に LE32 を書き出す。
                    813: bool
                    814: VirtIODevice::ReqWriteLE32(VirtIOReq& req, uint32 data)
                    815: {
                    816:        if (ReqWriteLE16(req, data & 0xffff) == false) {
                    817:                return false;
                    818:        }
                    819:        if (ReqWriteLE16(req, (data >> 16)) == false) {
                    820:                return false;
                    821:        }
                    822:        return true;
                    823: }
                    824: 
                    825: // この req から dst に dstlen バイト読み込む。
                    826: // dstlen のうち読み込めなかったバイト数を返す (すべて読み込めたら 0 を返す)。
                    827: uint32
                    828: VirtIODevice::ReqReadRegion(VirtIOReq& req, uint8 *dst, uint32 dstlen)
                    829: {
                    830:        uint8 *d = dst;
                    831: 
                    832:        while (dstlen != 0) {
                    833:                if (req.reof()) {
                    834:                        break;
                    835:                }
                    836: 
                    837:                // 今回読み込むバイト数と読み出し元 VM アドレス。
                    838:                uint32 len = std::min(req.rbuf[req.rseg].len - req.roff, dstlen);
                    839:                uint32 addr = req.rbuf[req.rseg].addr + req.roff;
                    840:                // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。
                    841:                // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない)
                    842:                // mainbus 経由でアクセスする。
                    843:                bool ok = mainram->ReadMem(addr, d, len);
                    844:                if (__predict_true(ok)) {
                    845:                        d += len;
                    846:                } else {
                    847:                        for (uint32 end = addr + len; addr < end; ) {
                    848:                                *d++ = ReadU8(addr++);
                    849:                        }
                    850:                }
                    851:                // この加算でセグメント長を超えることはない。
                    852:                req.roff += len;
                    853:                if (req.roff == req.rbuf[req.rseg].len) {
                    854:                        req.rseg++;
                    855:                        req.roff = 0;
                    856:                }
                    857:                dstlen -= len;
                    858:        }
                    859: 
                    860:        return dstlen;
                    861: }
                    862: 
                    863: // src から req に srclen バイト書き出す。
                    864: // srclen のうち書き出せなかったバイト数を返す (すべて書き出せたら 0 を返す)。
                    865: uint32
                    866: VirtIODevice::ReqWriteRegion(VirtIOReq& req, const uint8 *src, uint32 srclen)
                    867: {
                    868:        const uint8 *s = src;
                    869: 
                    870:        while (srclen != 0) {
                    871:                if (req.weof()) {
                    872:                        break;
                    873:                }
                    874: 
                    875:                // 今回書き出すバイト数と書き込み先 VM アドレス。
                    876:                uint32 len = std::min(req.wbuf[req.wseg].len - req.woff, srclen);
                    877:                uint32 addr = req.wbuf[req.wseg].addr + req.woff;
                    878:                // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。
                    879:                // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない)
                    880:                // mainbus 経由でアクセスする。
                    881:                bool ok = mainram->WriteMem(addr, s, len);
                    882:                if (__predict_true(ok)) {
                    883:                        s += len;
                    884:                } else {
                    885:                        for (uint32 end = addr + len; addr < end; ) {
                    886:                                WriteU8(addr++, *s);
                    887:                        }
                    888:                }
                    889:                // この加算でセグメント長を超えることはない。
                    890:                req.woff += len;
                    891:                if (req.woff == req.wbuf[req.wseg].len) {
                    892:                        req.wseg++;
                    893:                        req.woff = 0;
                    894:                }
                    895:                srclen -= len;
                    896:        }
                    897: 
                    898:        return srclen;
                    899: }
                    900: 
1.1       root      901: // 裏スレッドからの処理完了メッセージ通知。(VM スレッドで実行される)
                    902: // arg はキュー番号。
                    903: void
                    904: VirtIODevice::DoneMessage(MessageID msgid_, uint32 arg)
                    905: {
                    906:        int idx = arg;
                    907:        VirtQueue *q = &vqueues[idx];
                    908: 
                    909:        Done(q);
                    910: }
                    911: 
                    912: // ディスクリプタ処理が完了したので、必要なら割り込みを上げる。
                    913: // (VM スレッドで呼ぶこと)
                    914: void
                    915: VirtIODevice::Done(VirtQueue *q)
                    916: {
                    917:        // (必要なら) 割り込みを上げる。
                    918:        uint16 flag = ReadLE16(q->driver + 0);
                    919:        if ((flag & VIRTQ_AVAIL_F_NO_INTERRUPT) == 0) {
                    920:                intr_status |= 0x01;
                    921:                ChangeInterrupt();
                    922:        }
                    923: }
                    924: 
                    925: // 割り込み信号線の状態を変える。
                    926: void
                    927: VirtIODevice::ChangeInterrupt()
                    928: {
                    929:        assert(interrupt);
                    930:        interrupt->ChangeINT(this, (bool)intr_status);
                    931: }
                    932: 
                    933: // メインバスから U8 を読み込む。
                    934: uint32
                    935: VirtIODevice::ReadU8(uint32 addr)
                    936: {
1.1.1.2   root      937:        busdata data = mainbus->HVRead1(addr);
1.1       root      938:        return (uint8)data.Data();
                    939: }
                    940: 
                    941: // メインバスから LE16 を読み込む。
                    942: uint32
                    943: VirtIODevice::ReadLE16(uint32 addr)
                    944: {
1.1.1.2   root      945:        busdata data = mainbus->HVRead2(addr);
1.1       root      946:        return be16toh(data.Data());
                    947: }
                    948: 
                    949: // メインバスから LE32 を読み込む。
                    950: uint32
                    951: VirtIODevice::ReadLE32(uint32 addr)
                    952: {
1.1.1.2   root      953:        busdata data = mainbus->HVRead4(addr);
1.1       root      954:        return be32toh(data.Data());
                    955: }
                    956: 
                    957: // メインバスから LE64 を読み込む。
                    958: uint64
                    959: VirtIODevice::ReadLE64(uint32 addr)
                    960: {
                    961:        uint64 data;
                    962:        data  = (uint64)ReadLE32(addr + 0);
                    963:        data |= (uint64)ReadLE32(addr + 4) << 32;
                    964: 
                    965:        return data;
                    966: }
                    967: 
                    968: // メインバスに U8 を書き出す。
                    969: void
                    970: VirtIODevice::WriteU8(uint32 addr, uint32 data)
                    971: {
1.1.1.2   root      972:        mainbus->HVWrite1(addr, data);
1.1       root      973: }
                    974: 
                    975: // メインバスに LE16 を書き出す。
                    976: void
                    977: VirtIODevice::WriteLE16(uint32 addr, uint32 data)
                    978: {
1.1.1.2   root      979:        mainbus->HVWrite2(addr, htobe16(data));
1.1       root      980: }
                    981: 
                    982: // メインバスに LE32 を書き出す。
                    983: void
                    984: VirtIODevice::WriteLE32(uint32 addr, uint32 data)
                    985: {
1.1.1.2   root      986:        mainbus->HVWrite4(addr, htobe32(data));
1.1       root      987: }
                    988: 
                    989: // メインバスに LE64 を書き出す。
                    990: void
                    991: VirtIODevice::WriteLE64(uint32 addr, uint64 data)
                    992: {
                    993:        WriteLE32(addr + 0, data & 0xffffffff);
                    994:        WriteLE32(addr + 4, data >> 32);
                    995: }
                    996: 
                    997: // メインバスから副作用なく LE16 を読み出す。
                    998: uint32
                    999: VirtIODevice::PeekLE16(uint32 addr) const
                   1000: {
                   1001:        uint32 data;
1.1.1.2   root     1002:        data  = mainbus->Peek1(addr + 0);
                   1003:        data |= mainbus->Peek1(addr + 1) << 8;
1.1       root     1004:        return data;
                   1005: }
                   1006: 
                   1007: // メインバスから副作用なく LE32 を読み出す。
                   1008: uint32
                   1009: VirtIODevice::PeekLE32(uint32 addr) const
                   1010: {
                   1011:        uint32 data;
1.1.1.2   root     1012:        data  = mainbus->Peek1(addr + 0);
                   1013:        data |= mainbus->Peek1(addr + 1) << 8;
                   1014:        data |= mainbus->Peek1(addr + 2) << 16;
                   1015:        data |= mainbus->Peek1(addr + 3) << 24;
1.1       root     1016:        return data;
                   1017: }
                   1018: 
                   1019: // DEVICE_FEATURES にビットを立てる。初期化用。
                   1020: void
                   1021: VirtIODevice::SetDeviceFeatures(int feature)
                   1022: {
1.1.1.2   root     1023:        uint sel = feature / 32;
                   1024:        uint bit = feature % 32;
1.1       root     1025:        assert(sel < MAX_FEATURES_SEL);
                   1026:        device_features[sel] |= (1U << bit);
                   1027: }
                   1028: 
                   1029: // DRIVER_FEATURES のビットが立っていれば true を返す。
                   1030: bool
                   1031: VirtIODevice::GetDriverFeatures(int feature) const
                   1032: {
1.1.1.2   root     1033:        uint sel = feature / 32;
                   1034:        uint bit = feature % 32;
1.1       root     1035:        assert(sel < MAX_FEATURES_SEL);
                   1036:        return (driver_features[sel] & (1U << bit));
                   1037: }
                   1038: 
                   1039: // FEATURES 名を返す。(共通部分)
                   1040: const char *
1.1.1.2   root     1041: VirtIODevice::GetFeatureName(uint feature) const
1.1       root     1042: {
                   1043:        static std::pair<uint, const char *> names[] = {
1.1.1.2   root     1044:                { VIRTIO_F_RING_INDIRECT_DESC,  "INDIRECT" },
1.1       root     1045:                { VIRTIO_F_RING_EVENT_IDX,              "RING_EVENT" },
                   1046:                { VIRTIO_F_VERSION_1,                   "VER1" },
                   1047:                { VIRTIO_F_ACCESS_PLATFORM,             "ACCESS_PLATFORM" },
                   1048:                { VIRTIO_F_RING_PACKED,                 "RING_PACK" },
                   1049:                { VIRTIO_F_IN_ORDER,                    "IN_ORDER" },
                   1050:                { VIRTIO_F_ORDER_PLATFORM,              "ORDER_PLATFORM" },
                   1051:                { VIRTIO_F_SF_IOV,                              "SF_IOV" },
                   1052:                { VIRTIO_F_NOTIFICATION_DATA,   "NOTIFICATION_DATA" },
                   1053:        };
                   1054: 
                   1055:        for (auto& p : names) {
                   1056:                if (feature == p.first) {
                   1057:                        return p.second;
                   1058:                }
                   1059:        }
                   1060:        return NULL;
                   1061: }
                   1062: 
                   1063: 
                   1064: //
                   1065: // VirtIONone (空きスロット用)
                   1066: //
                   1067: 
                   1068: // コンストラクタ
                   1069: VirtIONoneDevice::VirtIONoneDevice()
                   1070:        : inherited(OBJ_NONE)
                   1071: {
1.1.1.6   root     1072:        SetName("VirtIONone");
1.1       root     1073: }
                   1074: 
                   1075: // デストラクタ
                   1076: VirtIONoneDevice::~VirtIONoneDevice()
                   1077: {
                   1078: }
                   1079: 
                   1080: busdata
1.1.1.2   root     1081: VirtIONoneDevice::ReadPort(uint32 offset)
1.1       root     1082: {
1.1.1.2   root     1083:        busdata data = PeekPort(offset);
1.1       root     1084: 
1.1.1.2   root     1085:        if (__predict_false(loglevel >= 1)) {
                   1086:                uint32 addr = offset << 2;
                   1087:                switch (addr) {
                   1088:                 case VirtIO::MAGIC_VALUE:
                   1089:                        putlogn("MAGIC_VALUE -> $%08x", data.Data());
                   1090:                        break;
1.1       root     1091: 
1.1.1.2   root     1092:                 case VirtIO::DEVICE_ID:
                   1093:                        putlogn("DEVICE_ID -> $%08x", data.Data());
                   1094:                        break;
1.1       root     1095: 
1.1.1.2   root     1096:                 default:
                   1097:                        putlogn("REG%03x -> $%08x", addr, data.Data());
                   1098:                        break;
                   1099:                }
1.1       root     1100:        }
1.1.1.2   root     1101: 
                   1102:        data |= BusData::Size4;
1.1       root     1103:        return data;
                   1104: }
                   1105: 
                   1106: busdata
1.1.1.2   root     1107: VirtIONoneDevice::WritePort(uint32 offset, uint32 data)
1.1       root     1108: {
1.1.1.2   root     1109:        return BusData::BusErr;
1.1       root     1110: }
                   1111: 
                   1112: busdata
1.1.1.2   root     1113: VirtIONoneDevice::PeekPort(uint32 offset)
1.1       root     1114: {
1.1.1.2   root     1115:        uint32 addr = offset << 2;
1.1       root     1116: 
1.1.1.2   root     1117:        switch (addr) {
1.1       root     1118:         case VirtIO::MAGIC_VALUE:
1.1.1.2   root     1119:                return VirtIO::MAGIC_STRING;
                   1120: 
1.1       root     1121:         case VirtIO::DEVICE_ID:
1.1.1.2   root     1122:                return VirtIO::DEVICE_ID_INVALID;
1.1       root     1123: 
                   1124:         default:
1.1.1.2   root     1125:                return 0xffffffff;
1.1       root     1126:        }
                   1127: }
                   1128: 
                   1129: 
                   1130: //
                   1131: // VirtIOThread
                   1132: //
                   1133: 
                   1134: // コンストラクタ
                   1135: VirtIOThread::VirtIOThread(VirtIODevice *parent_)
                   1136:        : inherited(OBJ_NONE)
                   1137: {
                   1138:        parent = parent_;
                   1139:        SetName(parent->GetName());
1.1.1.5   root     1140: 
                   1141:        // コンストラクト後ただちにログ出力できるようここで一度追従しておく。
                   1142:        // 以降は親クラス(表スレッド)の SetLogLevel() で変更する。
                   1143:        loglevel = parent->loglevel;
1.1       root     1144: }
                   1145: 
                   1146: // デストラクタ
                   1147: VirtIOThread::~VirtIOThread()
                   1148: {
                   1149:        TerminateThread();
                   1150: }
                   1151: 
                   1152: // 本当は ResetHard() で処理中のものをとめたほうがいいんだろうけど。
                   1153: 
                   1154: // スレッドの終了を指示
                   1155: void
                   1156: VirtIOThread::Terminate()
                   1157: {
1.1.1.6   root     1158:        std::lock_guard<std::mutex> lock(mtx);
1.1       root     1159:        request |= REQ_TERMINATE;
                   1160:        cv.notify_one();
                   1161: }
                   1162: 
                   1163: // ゲストからの QUEUE_NOTIFY 要求。(VM スレッドで呼ばれる)
                   1164: void
1.1.1.2   root     1165: VirtIOThread::RequestQueueNotify(uint idx)
1.1       root     1166: {
1.1.1.6   root     1167:        std::lock_guard<std::mutex> lock(mtx);
1.1       root     1168:        request |= REQ_QUEUE(idx);
                   1169:        cv.notify_one();
                   1170: }
                   1171: 
                   1172: // スレッド
                   1173: void
                   1174: VirtIOThread::ThreadRun()
                   1175: {
1.1.1.2   root     1176:        // どっちだろうか
                   1177:        SetThreadAffinityHint(AffinityClass::Light);
                   1178: 
1.1       root     1179:        for (;;) {
                   1180:                uint32 req;
                   1181: 
                   1182:                // 何か起きるまで待つ。
                   1183:                {
                   1184:                        std::unique_lock<std::mutex> lock(mtx);
                   1185:                        cv.wait(lock, [&] { return (request != 0); });
                   1186:                        req = request;
                   1187:                        request = 0;
                   1188:                }
                   1189: 
                   1190:                if ((req & REQ_TERMINATE)) {
                   1191:                        // 終了するので、他のフラグは無視。
                   1192:                        break;
                   1193:                }
                   1194: 
                   1195:                // idx 番目のキューに QUEUE_NOTIFY が指示された。
                   1196:                for (; req != 0; ) {
                   1197:                        int idx = __builtin_ctz(req);
                   1198:                        // 裏スレッドで Device クラスの関数を実行する。ややこしいので注意。
                   1199:                        parent->QueueNotify(idx);
                   1200:                        req &= ~(1U << idx);
                   1201:                }
                   1202:        }
                   1203: }
                   1204: 
                   1205: 
                   1206: //
                   1207: // VirtQueue
                   1208: //
                   1209: 
                   1210: // コンストラクタ
1.1.1.3   root     1211: VirtQueue::VirtQueue(VirtIODevice *parent_, int idx_, const std::string& name_,
                   1212:        int num_max_)
1.1       root     1213: {
1.1.1.3   root     1214:        parent = parent_;
1.1       root     1215:        idx = idx_;
                   1216:        name = name_;
                   1217:        num_max = num_max_;
                   1218: }
1.1.1.3   root     1219: 
                   1220: // QUEUE_READY の代入。
                   1221: void
                   1222: VirtQueue::SetReady(uint32 val)
                   1223: {
                   1224:        if (val != ready) {
                   1225:                ready = val;
                   1226:                parent->QueueReadyChanged(this);
                   1227:        }
                   1228: }
1.1.1.5   root     1229: 
                   1230: 
                   1231: //
                   1232: // VirtIOReq
                   1233: //
                   1234: 
                   1235: // 読み込みセグメントの先頭からの現在位置を返す。
                   1236: uint32
                   1237: VirtIOReq::rpos() const
                   1238: {
                   1239:        uint32 totalpos = 0;
                   1240: 
                   1241:        for (int i = 0; i < rseg; i++) {
                   1242:                totalpos += rbuf[i].len;
                   1243:        }
                   1244:        if (rseg < rbuf.size()) {
                   1245:                totalpos += roff;
                   1246:        }
                   1247:        return totalpos;
                   1248: }
                   1249: 
                   1250: // 書き込みセグメントの先頭からの現在位置を返す。
                   1251: uint32
                   1252: VirtIOReq::wpos() const
                   1253: {
                   1254:        uint32 totalpos = 0;
                   1255: 
                   1256:        for (int i = 0; i < wseg; i++) {
                   1257:                totalpos += wbuf[i].len;
                   1258:        }
                   1259:        if (wseg < wbuf.size()) {
                   1260:                totalpos += woff;
                   1261:        }
                   1262:        return totalpos;
                   1263: }

unix.superglobalmegacorp.com

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