int main() { #ifndef ONLINE_JUDGE //freopen("all.in", "r", stdin); //freopen("out", "w", stdout); #endif int i, ii, j, ans; while(scanf("%d%d", &k, &n) && n && k) { for(i = 1; i <= n; i ++){ scanf("%s", a[i].name); for(j = 1; j <= k; j ++) scanf("%d", &a[i].books[j]); } /*for books*/ for (ans = 0, i = 1; i <= n; i ++) { for (top = 0, ii = 1; ii <= n; ii ++) for (j = 1; j <= k; j ++) if (a[ii].books[j] == i) q[top++] = ii; if (vio(i)) ans ++; } if (ans == 0) printf ("NO PROBLEMS FOUND\n"); else if (ans == 1) printf ("1 PROBLEM FOUND\n"); else printf ("%d PROBLEMS FOUND\n", ans); } return 0; }
std::pair<bool, bool> MemoryType::checkAndMergeMemType(size_t ofs, const RsType* type) { if (typedata.size() == 0) // no types registered yet return mtyFailed(); size_t newStart = ofs; size_t newLength = type->getByteSize(); if ( diagnostics::message(diagnostics::memory) ) { std::stringstream msg; msg << "++ checkAndMergeMemType ofs: " << newStart << " (base = " << startAddress << ")" << " length: " << newLength << std::endl; RuntimeSystem::instance().printMessage( msg.str() ); } // Get a range of entries which overlap with [newStart,newTiEnd) TiIterPair res = ::getOverlappingTypeInfos(typedata, newStart, newLength); TiIter itLower = res.first; TiIter itUpper = res.second; // Case 0: There are types registered, but not ϵ [newStart, newTiEnd) if (itLower == itUpper) return mtyFailed(); // Case 1: New entry is overlapped by one old entry, // i.e. [itLower,itUpper) contains only one entry TiIter incrementedLower = itLower; ++incrementedLower; if (incrementedLower == itUpper) { const RsType* oldType = itLower->second; size_t oldStart = itLower->first; size_t oldLength = oldType->getByteSize(); std::ptrdiff_t diff = oldStart - newStart; // was: if( (oldStart <= newStart) && (oldTiEnd >= newTiEnd) ) if ((diff <= 0) && (newLength <= (diff + oldLength))) { //Check if new entry is consistent with old one bool new_type_ok = oldType->checkSubtypeRecursive( newStart - oldStart, type ); if( !new_type_ok ) { // \todo \ofs startAddress.local + newStart RuntimeViolation vio(RuntimeViolation::INVALID_TYPE_ACCESS, composeVioMessage(startAddress.local + newStart, newLength, type, *this) ); vio.descStream() << "Previously registered Type completely overlaps new Type in an inconsistent way:" << std::endl << "Containing Type " << oldType->getName() << " (" << oldStart << "," << (oldStart + oldLength) << ") base = " << startAddress << std::endl; RuntimeSystem::instance().violationHandler(vio); return mtyFailed(); } else { // successful, no need to add because the type is already contained in bigger one // effectively type has already been “merged”. return mtyNoUpdate(); } } } // Case 2: Iterate over overlapping old types and check consistency for(TypeData::iterator i = itLower; i != itUpper; ++i ) { const RsType* curType = i->second; size_t curStart = i->first; size_t curLength = curType->getByteSize(); std::ptrdiff_t diff = curStart - newStart; // std::cout << " >> " << diff << " #" << newLength << " #" << curLength << std::endl; // was: if ((curStart < newStart) || (newTiEnd < curEnd)) if ((diff < 0) || (newLength < (diff + curLength))) { // \todo \ofs startAddress.local + newStart RuntimeViolation vio(RuntimeViolation::INVALID_TYPE_ACCESS, composeVioMessage(startAddress.local + newStart, newLength, type, *this) ); vio.descStream() << "Previously registered Type overlaps new Type in an inconsistent way:" << std::endl << "Overlapping Type " << curType->getName() << " (" << curStart << "," << (curStart + curLength) << ") base = " << startAddress << std::endl; RuntimeSystem::instance().violationHandler(vio); return mtyFailed(); } const RsType* sub = type->getSubtypeRecursive(diff /*curStart - newStart*/, curLength); if (sub != curType) { // \todo \ofs startAddress.local + newStart RuntimeViolation vio(RuntimeViolation::INVALID_TYPE_ACCESS, composeVioMessage(startAddress.local + newStart, newLength, type, *this) ); vio.descStream() << "Newly registered Type completely overlaps a previous registered Type in an inconsistent way:" << std::endl << "Overlapping Type " << curType->getName() << " (" << curStart << "," << (curStart + curLength) << ") base = " << startAddress << std::endl; RuntimeSystem::instance().violationHandler(vio); return mtyFailed(); } } //All consistent - old typeInfos are replaced by big new typeInfo (merging) typedata.erase(itLower, itUpper); insert( typedata, TypeData::value_type(ofs, type) ); // if we have knowledge about the type in memory, we also need to update the // information about "dereferentiable" memory regions i.e. pointer const long blocksize = blockSize(); Location addr = ::add(startAddress, ofs, blocksize); RuntimeSystem& rs = rtedRTS(this); rs.getPointerManager().createPointer(addr, type, blocksize); return mtyMerged(); }
int main() { VirtioDriver vio(VIRTIO_0_BASE); vio.init(); kout << "Magic value is " << Hex(vio.reg32<VirtioDriver::V2_MagicValue>()) << "\n"; kout << "Version = " << vio.reg32<VirtioDriver::V2_Version>() << "\n"; kout << "VendorID = " << Hex(vio.reg32<VirtioDriver::V2_VendorID>()) << "\n"; kout << "DeviceID = " << Hex(vio.reg32<VirtioDriver::V2_DeviceID>()) << "\n"; kout << "HostFeatures = " << Hex(vio.reg32<VirtioDriver::V1_HostFeatures>()) << "\n"; kout << "GuestPageSize = " << Hex(vio.reg32<VirtioDriver::V1_GuestPageSize>()) << "\n"; kout << "DeviceStatus = " << Hex(vio.reg32<VirtioDriver::V1_Status>()) << "\n"; kout << "QueueNumMax = " << vio.reg32<VirtioDriver::V1_QueueNumMax>() << "\n"; auto blkConf = vio.regcopy<VirtioBlockConfig,VirtioDriver::V1_Config>(); blkConf.dump(); // return 0; // 至少包含2个对齐的PAGE char queueBuffer[VirtioDriver::PAGE_SIZE_4KB*3]; // 对齐处的地址 uint64_t pageAddr = alignAhead(reinterpret_cast<uint64_t>(queueBuffer),VirtioDriver::PAGE_SIZE_4KB); // legacy需要3个,[0]=8byte,3fields, [1]=data,[2]=1byte status size_t descrNum = 4; uint16_t startDescrIndex=1; constexpr size_t readBytes = // 3 // 512*3-1 // invalid 512*3 // 必须是512的n倍 ; // qsize // mem_size // VirtioQueueLayout vq(reinterpret_cast<void*>(pageAddr),descrNum,VirtioDriver::USED_RING_ALIGNMENT); auto memSize = vq.memSize(); kout << "virtqueue memSize = " << memSize << "\n"; // 应当清0 std::memset(vq.queueBase(), 0, memSize); // reqeust size_t blkNum = 1; size_t reqBufSize = VirtioBlockRequestRef::memSize(blkNum); if(reqBufSize >= readBytes + 512) { kout << FATAL << "req size overflows\n"; return 1; } // 至少包含readBytes个 char reqBuf[readBytes+512]; VirtioBlockRequestRef vreq(reqBuf,blkNum,VirtioBlockRequestRef::REQ_IN,0); const char * invalidStr = "if you see this, then it is invalid\n"; std::memcpy(vreq.data(),invalidStr,std::strlen(invalidStr)); VirtioQueueDescriptor * descs[3]; vq.allocateDescriptros(descs, 3); vq.chainDescriptors(descs, 3); // descs[0] // DW = DeviceWriteOnly,DR = DeviceReadOnly // [0]=header,DR,[1]=status,DW[2]=empty buffer,DW // or // [0] = header + status + empty buffer, DW // 前一个用于legacy模式 auto descTable = vq.descTable(); new (&descTable[startDescrIndex]) VirtioQueueDescriptor(reinterpret_cast<uint64_t>(vreq.base()),16,bitOnes<VirtioQueueDescriptor::VIRTQ_DESC_F_NEXT>(),startDescrIndex+1); new (&descTable[startDescrIndex+1]) VirtioQueueDescriptor(descTable[startDescrIndex+1].addr() + 16,readBytes,bitOnes<VirtioQueueDescriptor::VIRTQ_DESC_F_NEXT,VirtioQueueDescriptor::VIRTQ_DESC_F_WRITE>(),startDescrIndex+2); new (&descTable[startDescrIndex+2]) VirtioQueueDescriptor(descTable[startDescrIndex+2].addr() + readBytes,1,bitOnes<VirtioQueueDescriptor::VIRTQ_DESC_F_WRITE>(),0); // 注意, old_idx和new_idx之间的差值就是本次请求的数目 auto & avRef = vq.availRing(); avRef.idx(1); // avRef.ring()[0]=startDescrIndex;// header // avRef.ring()[1]=startDescrIndex + 1; /* 下面这些寄存器只写 case VIRTIO_MMIO_DEVICE_FEATURES_SEL: case VIRTIO_MMIO_DRIVER_FEATURES: case VIRTIO_MMIO_DRIVER_FEATURES_SEL: case VIRTIO_MMIO_GUEST_PAGE_SIZE: case VIRTIO_MMIO_QUEUE_SEL: case VIRTIO_MMIO_QUEUE_NUM: case VIRTIO_MMIO_QUEUE_ALIGN: case VIRTIO_MMIO_QUEUE_NOTIFY: case VIRTIO_MMIO_INTERRUPT_ACK: // 下面这些寄存器只读 case VIRTIO_MMIO_MAGIC_VALUE: case VIRTIO_MMIO_VERSION: case VIRTIO_MMIO_DEVICE_ID: case VIRTIO_MMIO_VENDOR_ID: case VIRTIO_MMIO_DEVICE_FEATURES: case VIRTIO_MMIO_QUEUE_NUM_MAX: case VIRTIO_MMIO_INTERRUPT_STATUS: */ /* * The virtual queue is configured as follows: 1. Select the queue writing its index (first queue is 0) to QueueSel. 2. Check if the queue is not already in use: read QueuePFN, expecting a returned value of zero (0x0). 3. Read maximum queue size (number of elements) from QueueNumMax. If the returned value is zero (0x0) the queue is not available. 4. Allocate and zero the queue pages in contiguous virtual memory, aligning the Used Ring to an optimal boundary (usually page size). The driver should choose a queue size smaller than or equal to QueueNumMax. 5. Notify the device about the queue size by writing the size to QueueNum. 6. Notify the device about the used alignment by writing its value in bytes to QueueAlign. 7. Write the physical number of the first page of the queue to the QueuePFN register. * * */ vio.reg32<VirtioDriver::V1_QueueSel>() = 0; // set current vio.reg32<VirtioDriver::V1_QueueNum>()=descrNum; // set current queue size vio.reg32<VirtioDriver::V1_QueuePFN>() = pageAddr / VirtioDriver::PAGE_SIZE_4KB; // 设置PFN // notify index 0 completed vio.reg32<VirtioDriver::V1_QueueNotify>()=0; // which queue? // wait to complete delayCPU(1000*1000); kout << "=====read data is \n"; kout.print(reinterpret_cast<const char*>(vreq.data()),readBytes); kout << "\n=================\n"; /* Historically, many drivers ignored the len value, as a result, many devices set len incorrectly. Thus, when using the legacy interface, it is generally a good idea to ignore the len value in used ring entries if possible. Specific known issues are listed per device type. 对于block device, When using the legacy interface, transitional drivers SHOULD ignore the len value in used ring entries. Note: Historically, some devices put the total descriptor length, or the total length of device-writable buffers there, even when only the status byte was actually written. 也就是说,legacy 模式下的len应当忽略 在实践中,len返回的总是readBytes + 1,因此应当忽略。 */ // 读取usedRing // 同样,old_idx和new_idx之间的差值也体现了本次完成的数目 auto &usedRingRef = vq.usedRing(); kout << "used ring idx = " << usedRingRef.idx() << "\n"; kout << "ring[0]{id,len} = " << usedRingRef.ring()[0]._id << "," << usedRingRef.ring()[0]._len<< "\n"; // kout << "ring[1]{id,len} = " << usedRingRef.ring()[1]._id << "," << usedRingRef.ring()[1]._len<< "\n"; return 0; }