/** * Transfer data from the specified array to this process's virtual memory. This method handles * address translation details. This method must <i>not</i> destroy the current process if an * error occurs, but instead should return the number of bytes successfully copied (or zero if no * data could be copied). * * @param vaddr the first byte of virtual memory to write. * @param data the array containing the data to transfer. * @param offset the first byte to transfer from the array. * @param length the number of bytes to transfer from the array to virtual memory. * @return the number of bytes successfully transferred. */ public int writeVirtualMemory(int vaddr, byte[] data, int offset, int length) { Lib.assertTrue(offset >= 0 && length >= 0 && offset + length <= data.length); byte[] memory = Machine.processor().getMemory(); int transferred = 0; while (length > 0 && offset < data.length) { int addrOffset = vaddr % 1024; int virtualPage = vaddr / 1024; if (virtualPage >= pageTable.length || virtualPage < 0) { break; } TranslationEntry pte = pageTable[virtualPage]; if (!pte.valid || pte.readOnly) { break; } pte.used = true; pte.dirty = true; int physPage = pte.ppn; int physAddr = physPage * 1024 + addrOffset; int transferLength = Math.min(data.length - offset, Math.min(length, 1024 - addrOffset)); System.arraycopy(data, offset, memory, physAddr, transferLength); vaddr += transferLength; offset += transferLength; length -= transferLength; transferred += transferLength; } return transferred; }
private int handleWrite(int a0, int bufaddr, int count) { OpenFile file = openfiles.get(a0); if (file == null) return -1; byte[] transfer_buffer = new byte[Processor.pageSize]; int total_transfer = 0; while (count > 0) { int readlen = Math.min(Processor.pageSize, count); int actualread = readVirtualMemory(bufaddr, transfer_buffer, 0, readlen); if (actualread == -1) return -1; if (actualread < readlen) return -1; int written_bytes = file.write(transfer_buffer, 0, actualread); if (written_bytes != actualread) { return -1; } count -= actualread; bufaddr += actualread; total_transfer += actualread; } return total_transfer; }