--- nono/vm/virtio_block.cpp 2026/04/29 17:05:32 1.1.1.3 +++ nono/vm/virtio_block.cpp 2026/04/29 17:05:59 1.1.1.6 @@ -52,21 +52,24 @@ VirtIOBlockDevice::VirtIOBlockDevice(uin { id = id_; - // 短縮形 - AddAlias(string_format("vblk%u", id)); + // 割り込み名(とログ名) + snprintf(intrname, sizeof(intrname), "VIOBlk%u", id); + SetName(intrname); + ClearAlias(); + AddAlias(intrname); + + image.SetName(intrname); device_id = VirtIO::DEVICE_ID_BLOCK; int num_max = 32; vqueues.emplace_back(this, 0, "RequestQ", num_max); blocksize = 512; - // 割り込み名 - snprintf(intrname, sizeof(intrname), "VIOBlk%u", id); // 完了通知メッセージ msgid = MessageID::VIRTIO_BLOCK_DONE(id); monitor = gMonitorManager->Regist(ID_MONITOR_VIRTIO_BLOCK(id), this); - monitor->func = ToMonitorCallback(&VirtIOBlockDevice::MonitorUpdate); + monitor->SetCallback(&VirtIOBlockDevice::MonitorScreen); monitor->SetSize(MONITOR_WIDTH, 2 + 4 * 1 + num_max + 3); } @@ -87,13 +90,14 @@ VirtIOBlockDevice::Init() const std::string wikey = string_format("virtio-block%u-writeignore", id); // オープン前に writeignore をチェック。see scsidev.cpp - write_ignore = gConfig->Find(wikey).AsInt(); + write_ignore = gConfig->Find(wikey).AsBool(); // オープン (値が空ならここには来ない) const ConfigItem& itemimg = gConfig->Find(imgkey); assert(itemimg.AsString().empty() == false); std::string path = gMainApp.NormalizePath(itemimg.AsString()); if (LoadDisk(path) == false) { + itemimg.Err("Could not open %s", path.c_str()); return false; } @@ -167,17 +171,17 @@ VirtIOBlockDevice::LoadDisk(const std::s } void -VirtIOBlockDevice::MonitorUpdate(Monitor *, TextScreen& screen) +VirtIOBlockDevice::MonitorScreen(Monitor *, TextScreen& screen) { int y = 0; screen.Clear(); - y = MonitorUpdateDev(screen, y); + y = MonitorScreenDev(screen, y); y++; - y = MonitorUpdateVirtQueue(screen, y, vqueues[0]); + y = MonitorScreenVirtQueue(screen, y, vqueues[0]); y++; - y = MonitorUpdateVirtQDesc(screen, y, vqueues[0]); + y = MonitorScreenVirtQDesc(screen, y, vqueues[0]); } // ディスクリプタを一つ処理する。 @@ -195,12 +199,12 @@ VirtIOBlockDevice::ProcessDesc(VirtIOReq // +8.L: 開始セクタ番号 if (ReqReadLE32(req, &type) == false) { - putlog(0, "Cannot read type in header (req.len=$%x)", req.len); + putlog(0, "Cannot read type in header"); return; } ReqReadLE32(req); // skip if (ReqReadLE64(req, §or) == false) { - putlog(0, "Cannot read sector in header (req.len=$%x)", req.len); + putlog(0, "Cannot read sector in header"); return; } putlog(3, "%s req.idx=%u type=%x sec=$%x'%08x", @@ -210,8 +214,8 @@ VirtIOBlockDevice::ProcessDesc(VirtIOReq // ヘッダ(16バイト) とステータスバイト(1バイト) を引いた部分。 // という求め方しかない。 uint32 datalen; - if (req.len >= 16 + 1) { - datalen = req.len - (16 + 1); + if (req.totallen() >= 16 + 1) { + datalen = req.totallen() - (16 + 1); } else { datalen = 0; } @@ -227,6 +231,10 @@ VirtIOBlockDevice::ProcessDesc(VirtIOReq access_write = q->last_avail_idx; break; + case VIRTIO_BLK_T_GET_ID: + status = CmdGetID(req, datalen); + break; + default: putlog(0, "%s req.type=%u (NOT IMPLEMENTED)", __func__, type); status = VIRTIO_BLK_S_UNSUPP; @@ -239,37 +247,15 @@ VirtIOBlockDevice::ProcessDesc(VirtIOReq uint32 VirtIOBlockDevice::CmdRead(VirtIOReq& req, uint64 sector, uint32 datalen) { - uint64 imgoffset = sector * 512; - - while (datalen != 0) { - if (req.curseg >= req.buf.size()) { - return VIRTIO_BLK_S_IOERR; - } - const auto seg = req.buf[req.curseg]; - uint32 segoff = req.pos - seg.pos; - std::vector databuf(seg.len - segoff); - - if (image.Read(databuf.data(), imgoffset, databuf.size()) == false) { - return VIRTIO_BLK_S_IOERR; - } - imgoffset += databuf.size(); + std::vector databuf(datalen); - // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。 - // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない) - // mainbus 経由でアクセスする。 - uint32 addr = seg.addr + segoff; - bool ok = mainram->WriteMem(addr, databuf.data(), databuf.size()); - if (__predict_false(ok == false)) { - for (auto s : databuf) { - WriteU8(addr++, s); - } - } - // 現在位置は必ずセグメント境界のはず。 - req.curseg++; - req.pos += databuf.size(); - - datalen -= databuf.size(); + if (image.Read(databuf.data(), sector * 512, databuf.size()) == false) { + return VIRTIO_BLK_S_IOERR; + } + if (ReqWriteRegion(req, databuf.data(), datalen) != 0) { + return VIRTIO_BLK_S_IOERR; } + return VIRTIO_BLK_S_OK; } @@ -277,37 +263,30 @@ VirtIOBlockDevice::CmdRead(VirtIOReq& re uint32 VirtIOBlockDevice::CmdWrite(VirtIOReq& req, uint64 sector, uint32 datalen) { - uint64 imgoffset = sector * 512; + std::vector databuf(datalen); - while (datalen != 0) { - if (req.curseg >= req.buf.size()) { - return VIRTIO_BLK_S_IOERR; - } - const auto seg = req.buf[req.curseg]; - uint32 segoff = req.pos - seg.pos; - std::vector databuf(seg.len - segoff); - - uint8 *d = &databuf[0]; - uint32 addr = seg.addr + segoff; - // 指定範囲は通常全域 RAM のはずなので mainram を直接呼ぶ。 - // 指定範囲が RAM からはみ出たりしていたら (通常まずありえない) - // mainbus 経由でアクセスする。 - bool ok = mainram->ReadMem(addr, databuf.data(), databuf.size()); - if (__predict_false(ok == false)) { - for (uint32 end = addr + databuf.size(); addr < end; ) { - *d++ = ReadU8(addr++); - } - } - // 現在位置は必ずセグメント境界のはず。 - req.curseg++; - req.pos += databuf.size(); + if (ReqReadRegion(req, databuf.data(), datalen) != 0) { + return VIRTIO_BLK_S_IOERR; + } + if (image.Write(databuf.data(), sector * 512, databuf.size()) == false) { + return VIRTIO_BLK_S_IOERR; + } - if (image.Write(databuf.data(), imgoffset, databuf.size()) == false) { - return VIRTIO_BLK_S_IOERR; - } - imgoffset += databuf.size(); + return VIRTIO_BLK_S_OK; +} + +// ID 取得コマンド (BLK_T_GET_ID) 実行。 +uint32 +VirtIOBlockDevice::CmdGetID(VirtIOReq& req, uint32 datalen) +{ + std::vector databuf(datalen); + + // Device ID string を返すらしいが、どういう文字列か分からん。 + // 20バイトで余りはゼロ埋め。20文字なら終端文字なしで 20文字有効。 + snprintf((char *)databuf.data(), datalen, "virtio-block%u", id); - datalen -= databuf.size(); + if (ReqWriteRegion(req, databuf.data(), datalen) != 0) { + return VIRTIO_BLK_S_IOERR; } return VIRTIO_BLK_S_OK;