--- nono/vm/virtio_base.cpp 2026/04/29 17:05:25 1.1 +++ nono/vm/virtio_base.cpp 2026/04/29 17:05:29 1.1.1.2 @@ -12,6 +12,7 @@ #include "goldfish_pic.h" #include "virtio_def.h" #include "mainbus.h" +#include "mainram.h" #include "scheduler.h" // @@ -19,7 +20,7 @@ // // コンストラクタ -VirtIODevice::VirtIODevice(int objid_, int slot_) +VirtIODevice::VirtIODevice(uint objid_, uint slot_) : inherited(objid_) { slot = slot_; @@ -61,18 +62,20 @@ VirtIODevice::Init() } mainbus = GetMainbusDevice(); + mainram = GetMainRAMDevice(); // GFPIC に割り込みを登録する。 // 継承側のコンストラクタで intrname の設定をしておくこと。 assert(intrname[0]); - int pic = (slot / 32) + 2; - int irq = (slot % 32) + 1; + uint pic = (slot / 32) + 2; + uint irq = (slot % 32) + 1; auto gfpic = GetGFPICDevice(pic); gfpic->RegistIRQ(irq, intrname, this); interrupt = gfpic; // DEVICE_FEATURES (共通部) を用意。 + SetDeviceFeatures(VIRTIO_F_RING_INDIRECT_DESC); SetDeviceFeatures(VIRTIO_F_VERSION_1); // 裏スレッドからの DONE コールバックを登録。 @@ -87,163 +90,87 @@ VirtIODevice::Init() void VirtIODevice::ResetHard(bool poweron) { - device_status = VirtIO::STATUS_RESET; - device_sel = 0; - driver_sel = 0; - - for (int i = 0; i < MAX_FEATURES_SEL; i++) { - driver_features[i] = 0; - } - - for (int i = 0; i < vqueues.size(); i++) { - auto& q = vqueues[i]; - q.idx = i; - // モニタの見栄えのため未設定時は無効値を入れておく - q.desc = 0xcccccccc; - q.driver = 0xcccccccc; - q.device = 0xcccccccc; - q.num = 0; - q.ready = 0; - q.last_avail_idx = 0; - } - vq = NULL; - - intr_status = 0; - ChangeInterrupt(); + Reset(); } +// BusIO のオフセットはこのポート幅で先頭から 0個目、1個目と数えるが、 +// VirtIO の仕様でレジスタは $00、$04 のようにアドレスで数えるので +// オフセットで渡されたものをもう一回アドレスに戻す…。 + // レジスタ部 (<0x100) はゲストエンディアン (BE) // コンフィグ部 (>=0x100) はリトルエンディアン。 busdata -VirtIODevice::Read8(uint32 addr) -{ - uint32 offset = addr & 0x1ff; - - if (offset < 0x100) { - uint32 data = GetReg(offset & ~3); - - switch (offset & 3) { - case 0: - return (data >> 24) & 0xff; - case 1: - return (data >> 16) & 0xff; - case 2: - return (data >> 8) & 0xff; - case 3: - return data & 0xff; - default: - __unreachable(); - } - } else { - // バイトイメージなのでそのまま。 - return device_config[offset - 0x100]; - } -} - -busdata -VirtIODevice::Read16(uint32 addr) +VirtIODevice::ReadPort(uint32 offset) { - uint32 offset = addr & 0x1ff; - uint32 data; + busdata data; - if (offset < 0x100) { - data = GetReg(offset & ~3); + data = PeekPort(offset); - if ((offset & 2) == 0) { - return (data >> 16) & 0xffff; - } else { - return data & 0xffff; - } - } else { - data = (device_config[offset - 0x100 + 0] << 8) - | (device_config[offset - 0x100 + 1]); - return data; - } -} - -busdata -VirtIODevice::Read32(uint32 addr) -{ - uint32 offset = addr & 0x1ff; - uint32 data; - - if (offset < 0x100) { - data = GetReg(offset); - if (loglevel >= 2) { - switch (offset) { + if (__predict_false(loglevel >= 2)) { + uint32 addr = offset << 2; + if (addr < 0x100) { + switch (addr) { case VirtIO::MAGIC_VALUE: - putlogn("MAGIC_VALUE -> $%08x", data); + putlogn("MAGIC_VALUE -> $%08x", data.Data()); break; case VirtIO::VERSION: - putlogn("VERSION -> $%08x", data); + putlogn("VERSION -> $%08x", data.Data()); break; case VirtIO::DEVICE_ID: - putlogn("DEVICE_ID -> $%08x", data); + putlogn("DEVICE_ID -> $%08x", data.Data()); break; case VirtIO::VENDOR_ID: - putlogn("VENDOR_ID -> $%08x", data); + putlogn("VENDOR_ID -> $%08x", data.Data()); break; case VirtIO::DEVICE_FEATURES: - putlogn("DEVICE_FEATURES[%x] -> $%08x", device_sel, data); + putlogn("DEVICE_FEATURES[%x] -> $%08x", + device_sel, data.Data()); break; case VirtIO::STATUS: - putlogn("STATUS -> $%08x%s", data, + putlogn("STATUS -> $%08x%s", data.Data(), VirtIO::StatusBits(data).c_str()); break; case VirtIO::QUEUE_NUM_MAX: - putlogn("QUEUE_NUM_MAX(%u) -> $%08x", queue_sel, data); + putlogn("QUEUE_NUM_MAX(%u) -> $%08x", queue_sel, data.Data()); break; case VirtIO::INTERRUPT_STATUS: - putlogn("INTERRUPT_STATUS -> $%08x", data); + putlogn("INTERRUPT_STATUS -> $%08x", data.Data()); break; default: - putlogn("REG%03x -> $%08x", offset, data); + putlogn("REG%03x -> $%08x", addr, data.Data()); break; } + } else { + putlogn("CONFIG:%03x -> $%08x", addr, data.Data()); } - return data; - } else { - data = (device_config[offset - 0x100 + 0] << 24) - | (device_config[offset - 0x100 + 1] << 16) - | (device_config[offset - 0x100 + 2] << 8) - | (device_config[offset - 0x100 + 3]); - putlog(2, "CONFIG:%03x -> $%08x", offset, data); - return data; } -} - -busdata -VirtIODevice::Write8(uint32 addr, uint32 data) -{ - putlog(0, "Write8($%08x) <- $%02x (NOT IMPLEMENTED)", addr, data); - return 0; -} -busdata -VirtIODevice::Write16(uint32 addr, uint32 data) -{ - putlog(0, "Write16($%08x) <- $%02x (NOT IMPLEMENTED)", addr, data); - return 0; + data |= BusData::Size4; + return data; } busdata -VirtIODevice::Write32(uint32 addr, uint32 data) +VirtIODevice::WritePort(uint32 offset, uint32 data) { - uint32 offset = addr & 0x1ff; + busdata r = BusData::Size4; - if (offset >= 0x100) { - putlog(1, "Write $%03x (Not writeable)", offset); - return 0; + uint32 addr = offset << 2; + if (addr >= 0x100) { + putlog(1, "Write $%03x (Not writeable)", addr); + return r; } - switch (offset) { + switch (addr) { case VirtIO::STATUS: // 0 を書き込むとデバイスリセット。 // 0 以外はステータスの書き込み。 device_status = data; putlog(2, "STATUS <- $%08x%s", device_status, VirtIO::StatusBits(device_status).c_str()); + if (device_status == 0) { + Reset(); + } break; case VirtIO::DEVICE_FEATURES_SEL: @@ -354,38 +281,32 @@ VirtIODevice::Write32(uint32 addr, uint3 break; default: - putlog(0, "Write $%03x <- $%08x (NOT IMPLEMENTED)", offset, data); + putlog(0, "Write $%03x <- $%08x (NOT IMPLEMENTED)", addr, data); break; } - return 0; + return r; } busdata -VirtIODevice::Peek8(uint32 addr) +VirtIODevice::PeekPort(uint32 offset) { - uint32 offset = addr & 0x1ff; + uint32 data; - if (offset < 0x100) { - uint32 data = GetReg(offset & ~3); + uint32 addr = offset << 2; - // レジスタ部は 32 ビット値で取得してゲストエンディアン(BE)に見せる。 - switch (offset & 3) { - case 0: - return (data >> 24) & 0xff; - case 1: - return (data >> 16) & 0xff; - case 2: - return (data >> 8) & 0xff; - case 3: - return data & 0xff; - default: - __unreachable(); - } + if (addr < 0x100) { + data = GetReg(addr); } else { // コンフィグ部はバイトイメージなのでそのまま。 - return device_config[offset - 0x100]; + addr -= 0x100; + data = (device_config[addr + 0] << 24) + | (device_config[addr + 1] << 16) + | (device_config[addr + 2] << 8) + | (device_config[addr + 3]); } + + return busdata(data); } // 下請け、デバイス情報部分。 @@ -396,7 +317,7 @@ VirtIODevice::MonitorUpdateDev(TextScree // 012345678901234567890123456789012345678901234567890123456789012345678901234 // DeviceType: 2(Block Device) DeviceAddr: $00000000 (Slot $00) - screen.Print(0, y, "DeviceType: %d(%s)", + screen.Print(0, y, "DeviceType: %u(%s)", device_id, VirtIO::DeviceIDStr(device_id).c_str()); screen.Print(43, y, "DeviceAddr: $%08x (Slot $%02x)", baseaddr + slot * 0x200, slot); @@ -437,7 +358,7 @@ VirtIODevice::MonitorUpdateVirtQueue(Tex // TableAddr: Desc=$00000000 Avail=$00000000(NoIntr) Used=$00000000(NoNotify) // Ring: LastAvail=$0000 Avail=$0000 (Head=$0000) Used=$0000 - screen.Print(0, y++, "VirtQueue%u: \"%s\" (NUM=%d/%d)", + screen.Print(0, y++, "VirtQueue%u: \"%s\" (NUM=%u/%u)", q.idx, q.name.c_str(), q.num, q.num_max); screen.Puts(1, y, "TableAddr:"); @@ -463,7 +384,7 @@ VirtIODevice::MonitorUpdateVirtQueue(Tex screen.Puts(1, y, "Ring:"); if (__predict_true(q.ready)) { uint16 aidx = PeekLE16(q.driver + 2); - uint16 head = PeekLE16(q.driver + 4 + (aidx % q.num) * 2); + uint16 head = PeekLE16(q.driver + 4 + q.Mod(aidx) * 2); uint16 uidx = PeekLE16(q.device + 2); screen.Print(12, y, "LastAvail=$%04x", q.last_avail_idx); @@ -506,11 +427,9 @@ VirtIODevice::MonitorUpdateVirtQDesc(Tex screen.Puts(x2, y, "ID Length"); y++; - uint num = q.num; - int ytop = y; int i; - for (i = 0; i < num; i++) { + for (i = 0; i < q.num; i++) { // Desc Table uint32 desc = q.desc + i * 16; uint32 addr = PeekLE32(desc + 0x00); @@ -542,19 +461,48 @@ VirtIODevice::MonitorUpdateVirtQDesc(Tex if (__predict_true(q.ready)) { uint avail_idx = PeekLE16(q.driver + 2); uint used_idx = PeekLE16(q.device + 2); - screen.Puts(x1 - 3, ytop + (avail_idx % num), "G>"); - screen.Puts(x1 + 5, ytop + (q.last_avail_idx % num), ""); + screen.Puts(x1 + 5, ytop + q.Mod(q.last_avail_idx), "SendMessage(msgid, q->idx); } } +// q->last_avail_idx の指すディスクリプタからの +// ディスクリプタチェイン req を構成する。 +// req は初期化後 .q のみ代入した状態で呼ぶこと。 +void +VirtIODevice::StartDesc(VirtIOReq& req) +{ + const VirtQueue *q = req.q; + uint32 flag; + uint32 idx; + + req.pos = 0; + req.len = 0; + + // 先頭のインデックス。 + idx = ReadLE16(q->driver + 4 + q->Mod(q->last_avail_idx) * 2); + if ((int32)idx<0) { + return; + } + req.idx = idx; + + do { + // desc[idx] を読み出す。 + uint32 descaddr = q->desc + idx * 16; + uint32 addr; + uint32 slen; + addr = ReadLE32(descaddr + 0); + slen = ReadLE32(descaddr + 8); + flag = ReadLE16(descaddr + 12); + idx = ReadLE16(descaddr + 14); // Next Index + + if ((flag & VIRTQ_DESC_F_INDIRECT)) { + AddIndirectDesc(req, addr, slen); + } else { + // R/W 属性は無視する。 + putlog(3, "req.buf[%u]: addr=$%08x off=$%08x len=$%04x", + (uint)req.buf.size(), addr, req.len, slen); + req.buf.emplace_back(addr, req.len, slen); + + // セグメントオフセットを記録した後で足す。 + req.len += slen; + } + } while ((flag & VIRTQ_DESC_F_NEXT)); +} + +// 間接ディスクリプタを追加する。 +void +VirtIODevice::AddIndirectDesc(VirtIOReq& req, uint32 table, uint32 tablelen) +{ + uint32 count = tablelen / 16; + uint32 flag; + uint32 idx; + + idx = 0; + do { + if (__predict_false(idx >= count)) { + // 指定されたテーブル領域外を指していたらどうする? + putlog(0, "Invalid indirect table index=%u (count=%u)", + idx, count); + return; + } + uint32 descaddr = table + idx * 16; + uint32 addr; + uint32 slen; + addr = ReadLE32(descaddr + 0); + slen = ReadLE32(descaddr + 8); + flag = ReadLE16(descaddr + 12); + idx = ReadLE16(descaddr + 14); + + putlog(3, "req.buf[%u]: addr=$%08x off=$%08x len=$%04x (Indirect)", + (uint)req.buf.size(), addr, req.len, slen); + + req.buf.emplace_back(addr, req.len, slen); + + // セグメントオフセットを記録した後で足す。 + req.len += slen; + } while ((flag & VIRTQ_DESC_F_NEXT)); +} + // ディスクリプタ処理完了。 void -VirtIODevice::CommitDesc(VirtQueue *q, uint32 idx, uint32 len) +VirtIODevice::CommitDesc(VirtIOReq& req) { + VirtQueue *q = req.q; + // Used Ring に記録。 uint16 used_idx = ReadLE16(q->device + 2); - WriteLE32(q->device + 4 + (used_idx % q->num) * 8 + 0, idx); - WriteLE32(q->device + 4 + (used_idx % q->num) * 8 + 4, len); + WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 0, req.idx); + WriteLE32(q->device + 4 + q->Mod(used_idx) * 8 + 4, req.pos); used_idx++; WriteLE16(q->device + 2, used_idx); @@ -648,6 +683,116 @@ VirtIODevice::CommitDesc(VirtQueue *q, u q->last_avail_idx = (uint16)(q->last_avail_idx + 1); } +// この req から1バイト読み込む。 +// 読み込めなければ -1 を返す。 +uint32 +VirtIODevice::ReqReadU8(VirtIOReq& req) +{ + if (req.pos >= req.len) { + return -1; + } + auto seg = req.buf[req.curseg]; + int segoff = req.pos - seg.pos; + uint8 data = ReadU8(seg.addr + segoff); + + req.pos++; + if (++segoff >= seg.len) { + req.curseg++; + } + return data; +} + +// この req から LE16 を読み込む。 +// 読み込めなければ -1 を返す。 +uint32 +VirtIODevice::ReqReadLE16(VirtIOReq& req) +{ + uint32 hi, lo; + + lo = ReqReadU8(req); + if ((int32)lo < 0) { + return lo; + } + hi = ReqReadU8(req); + if ((int32)hi < 0) { + return hi; + } + + return lo | (hi << 8); +} + +// この req から LE32 を読み込む。 +// 読み込めなければ -1 を返す。 +uint64 +VirtIODevice::ReqReadLE32(VirtIOReq& req) +{ + uint32 hi, lo; + + lo = ReqReadLE16(req); + if ((int32)lo < 0) { + return lo; + } + hi = ReqReadLE16(req); + if ((int32)hi < 0) { + return hi; + } + + return lo | (hi << 16); +} + +// この req から LE32 を読み込んで *retp に格納する。 +// 読み込めなければ false を返す。 +bool +VirtIODevice::ReqReadLE32(VirtIOReq& req, uint32 *retp) +{ + uint64 val = ReqReadLE32(req); + if ((int64)val < 0) { + return false; + } + + *retp = (uint32)val; + return true; +} + +// この req から LE64 を読み込んで *retp に格納する。 +// 読み込めなければ false を返す。 +bool +VirtIODevice::ReqReadLE64(VirtIOReq& req, uint64 *retp) +{ + uint64 hi, lo; + + lo = ReqReadLE32(req); + if ((int64)lo < 0) { + return false; + } + hi = ReqReadLE32(req); + if ((int64)hi < 0) { + return false; + } + + *retp = lo | (hi << 32); + return true; +} + +// この req に1バイト書き出す。 +bool +VirtIODevice::ReqWriteU8(VirtIOReq& req, uint32 data) +{ + if (req.pos >= req.len) { + return false; + } + + const auto seg = req.buf[req.curseg]; + int segoff = req.pos - seg.pos; + WriteU8(seg.addr + segoff, data); + + req.pos++; + if (++segoff >= seg.len) { + req.curseg++; + } + return true; +} + // 裏スレッドからの処理完了メッセージ通知。(VM スレッドで実行される) // arg はキュー番号。 void @@ -684,7 +829,7 @@ VirtIODevice::ChangeInterrupt() uint32 VirtIODevice::ReadU8(uint32 addr) { - busdata data = mainbus->HVRead8(addr); + busdata data = mainbus->HVRead1(addr); return (uint8)data.Data(); } @@ -692,7 +837,7 @@ VirtIODevice::ReadU8(uint32 addr) uint32 VirtIODevice::ReadLE16(uint32 addr) { - busdata data = mainbus->HVRead16(addr); + busdata data = mainbus->HVRead2(addr); return be16toh(data.Data()); } @@ -700,7 +845,7 @@ VirtIODevice::ReadLE16(uint32 addr) uint32 VirtIODevice::ReadLE32(uint32 addr) { - busdata data = mainbus->HVRead32(addr); + busdata data = mainbus->HVRead4(addr); return be32toh(data.Data()); } @@ -719,21 +864,21 @@ VirtIODevice::ReadLE64(uint32 addr) void VirtIODevice::WriteU8(uint32 addr, uint32 data) { - mainbus->HVWrite8(addr, data); + mainbus->HVWrite1(addr, data); } // メインバスに LE16 を書き出す。 void VirtIODevice::WriteLE16(uint32 addr, uint32 data) { - mainbus->HVWrite16(addr, htobe16(data)); + mainbus->HVWrite2(addr, htobe16(data)); } // メインバスに LE32 を書き出す。 void VirtIODevice::WriteLE32(uint32 addr, uint32 data) { - mainbus->HVWrite32(addr, htobe32(data)); + mainbus->HVWrite4(addr, htobe32(data)); } // メインバスに LE64 を書き出す。 @@ -749,8 +894,8 @@ uint32 VirtIODevice::PeekLE16(uint32 addr) const { uint32 data; - data = mainbus->Peek8(addr + 0); - data |= mainbus->Peek8(addr + 1) << 8; + data = mainbus->Peek1(addr + 0); + data |= mainbus->Peek1(addr + 1) << 8; return data; } @@ -759,68 +904,19 @@ uint32 VirtIODevice::PeekLE32(uint32 addr) const { uint32 data; - data = mainbus->Peek8(addr + 0); - data |= mainbus->Peek8(addr + 1) << 8; - data |= mainbus->Peek8(addr + 2) << 16; - data |= mainbus->Peek8(addr + 3) << 24; + data = mainbus->Peek1(addr + 0); + data |= mainbus->Peek1(addr + 1) << 8; + data |= mainbus->Peek1(addr + 2) << 16; + data |= mainbus->Peek1(addr + 3) << 24; return data; } -// ディスクリプタテーブルの idx 番目を desc に読み込む。 -uint32 -VirtIODevice::ReadDesc(const VirtQueue *q, VirtQDesc *desc, uint32 idx) -{ - uint32 len; - - uint32 descaddr = q->desc + idx * 16; - // addr は実際は 64 ビットだが上位は無視。 - desc->addr = ReadLE32(descaddr + 0); - len = ReadLE32(descaddr + 8); - desc->flag = ReadLE16(descaddr + 12); - desc->next = ReadLE16(descaddr + 14); - - desc->len = len; - return len; -} - -// req にデータセグメントを追加する。 -void -VirtIODevice::AddDataSegment(VirtIOReq *req, uint32 addr, uint32 len, - const char *msg) -{ - int i = req->buf.size(); - req->buf.emplace_back(addr, len); - putlog(3, "req.buf[%u]: addr=%x len=%x%s", i, addr, len, - (msg != NULL) ? msg : ""); -} - -// この Req のバッファに1バイト書き込む。 -bool -VirtIODevice::ReqAppendByte(VirtIOReq *req, uint32 data) -{ - assert(req); - - if (req->curseg >= req->buf.size()) { - return false; - } - - const auto seg = req->buf[req->curseg]; - WriteU8(seg.addr + req->offset, data); - - req->offset++; - if (req->offset >= seg.len) { - req->curseg++; - req->offset = 0; - } - return true; -} - // DEVICE_FEATURES にビットを立てる。初期化用。 void VirtIODevice::SetDeviceFeatures(int feature) { - int sel = feature / 32; - int bit = feature % 32; + uint sel = feature / 32; + uint bit = feature % 32; assert(sel < MAX_FEATURES_SEL); device_features[sel] |= (1U << bit); } @@ -829,18 +925,18 @@ VirtIODevice::SetDeviceFeatures(int feat bool VirtIODevice::GetDriverFeatures(int feature) const { - int sel = feature / 32; - int bit = feature % 32; + uint sel = feature / 32; + uint bit = feature % 32; assert(sel < MAX_FEATURES_SEL); return (driver_features[sel] & (1U << bit)); } // FEATURES 名を返す。(共通部分) const char * -VirtIODevice::GetFeatureName(int feature) const +VirtIODevice::GetFeatureName(uint feature) const { static std::pair names[] = { - { VIRTIO_F_RING_INDIRECT_DESC, "RING_INDIRECT" }, + { VIRTIO_F_RING_INDIRECT_DESC, "INDIRECT" }, { VIRTIO_F_RING_EVENT_IDX, "RING_EVENT" }, { VIRTIO_F_VERSION_1, "VER1" }, { VIRTIO_F_ACCESS_PLATFORM, "ACCESS_PLATFORM" }, @@ -876,61 +972,51 @@ VirtIONoneDevice::~VirtIONoneDevice() } busdata -VirtIONoneDevice::Read32(uint32 addr) +VirtIONoneDevice::ReadPort(uint32 offset) { - uint32 offset = addr & 0x1ff; - uint32 data; + busdata data = PeekPort(offset); - switch (offset) { - case VirtIO::MAGIC_VALUE: - data = VirtIO::MAGIC_STRING; - putlog(1, "MAGIC_VALUE -> $%08x", data); - break; + if (__predict_false(loglevel >= 1)) { + uint32 addr = offset << 2; + switch (addr) { + case VirtIO::MAGIC_VALUE: + putlogn("MAGIC_VALUE -> $%08x", data.Data()); + break; - case VirtIO::DEVICE_ID: - data = VirtIO::DEVICE_ID_INVALID; - putlog(1, "DEVICE_ID -> $%08x", data); - break; + case VirtIO::DEVICE_ID: + putlogn("DEVICE_ID -> $%08x", data.Data()); + break; - default: - data = 0xffffffff; - putlog(1, "REG%03x -> $%08x", offset, data); - break; + default: + putlogn("REG%03x -> $%08x", addr, data.Data()); + break; + } } + + data |= BusData::Size4; return data; } busdata -VirtIONoneDevice::Write32(uint32 addr, uint32 data) +VirtIONoneDevice::WritePort(uint32 offset, uint32 data) { - return busdata::BusErr; + return BusData::BusErr; } busdata -VirtIONoneDevice::Peek8(uint32 addr) +VirtIONoneDevice::PeekPort(uint32 offset) { - uint32 offset = addr & 0x1fc; - uint32 data; + uint32 addr = offset << 2; - switch (offset) { + switch (addr) { case VirtIO::MAGIC_VALUE: - data = VirtIO::MAGIC_STRING; - break; + return VirtIO::MAGIC_STRING; + case VirtIO::DEVICE_ID: - data = VirtIO::DEVICE_ID_INVALID; - break; - default: - data = 0xffffffff; - break; - } + return VirtIO::DEVICE_ID_INVALID; - switch (addr & 3) { - case 0: return (data >> 24); - case 1: return (data >> 16) & 0xff; - case 2: return (data >> 8) & 0xff; - case 3: return (data ) & 0xff; default: - __unreachable(); + return 0xffffffff; } } @@ -966,7 +1052,7 @@ VirtIOThread::Terminate() // ゲストからの QUEUE_NOTIFY 要求。(VM スレッドで呼ばれる) void -VirtIOThread::RequestQueueNotify(int idx) +VirtIOThread::RequestQueueNotify(uint idx) { std::unique_lock lock(mtx); request |= REQ_QUEUE(idx); @@ -977,6 +1063,9 @@ VirtIOThread::RequestQueueNotify(int idx void VirtIOThread::ThreadRun() { + // どっちだろうか + SetThreadAffinityHint(AffinityClass::Light); + for (;;) { uint32 req;