// care of Darrell Anderson // load a page from the executable (or zero if uninit data segment). // into the current address space. // void AddrSpace::LoadPage(OpenFile *executable, NoffHeader *noffH, int vpn) { int pageStart = vpn * PageSize; // page starting virtual address int pageEnd = (vpn + 1) * PageSize; // page ending virtual address int pagePhys; // page starting physical address int segStart; // segment (e.g. code) start va int segEnd; // segment (e.g. code) end va int offset; // offset into page int len; // bytes to read int foff; // file offset reading from ASSERT(0 <= vpn && vpn < (int)numPages); ASSERT(pageTable[vpn].virtualPage == vpn); pagePhys = pageTable[vpn].physicalPage * PageSize; // print a header summary for the first page (presumably faults first too) if (vpn == 0) { DEBUG('A', "LoadPage: codeSeg start=%d, len=%d\n", noffH->code.virtualAddr, noffH->code.size); DEBUG('A', " dataSeg start=%d, len=%d\n", noffH->initData.virtualAddr, noffH->initData.size); DEBUG('A', " zeroSeg start=%d, len=%d + stack=%d\n", // nastiness for programs without uninit seg, see comment below noffH->uninitData.virtualAddr ? noffH->uninitData.virtualAddr : noffH->initData.virtualAddr ? noffH->initData.virtualAddr + noffH->initData.size : noffH->code.virtualAddr + noffH->code.size, noffH->uninitData.size, UserStackSize); } // any code on this page? segStart = noffH->code.virtualAddr; segEnd = segStart + noffH->code.size; if (pageEnd > segStart && pageStart < segEnd) { offset = max(0, segStart - pageStart); len = PageSize - offset - max(0, pageEnd - segEnd); foff = noffH->code.inFileAddr + ((pageStart + offset) - segStart); ASSERT(0 <= offset && offset <= PageSize); ASSERT(0 <= len && len <= PageSize); ASSERT(offset/PageSize == (offset+len-1)/PageSize); // all same page DEBUG('A', "LoadPage: code vpn=%d, off=%d, len=%d\n", vpn, offset, len); executable->ReadAt(&machine->mainMemory[pagePhys+offset], len, foff); } // any initialized data on this page? segStart = noffH->initData.virtualAddr; segEnd = segStart + noffH->initData.size; if (pageEnd > segStart && pageStart < segEnd) { offset = max(0, segStart - pageStart); len = PageSize - offset - max(0, pageEnd - segEnd); foff = noffH->initData.inFileAddr + ((pageStart + offset) - segStart); ASSERT(0 <= offset && offset <= PageSize); ASSERT(0 <= len && len <= PageSize); ASSERT(offset/PageSize == (offset+len-1)/PageSize); // all same page DEBUG('A', "LoadPage: data vpn=%d, off=%d, len=%d\n", vpn, offset, len); executable->ReadAt(&machine->mainMemory[pagePhys+offset], len, foff); } // any uninitialized data or stack on this page? // if the program lacks a data segment or uninitialized data, // those virtualAddr fields in the noff header will be empty (zero). // because we always have a length (due to UserStackSize), make // sure we've got a valid start. that is, it can't be less than // the end of the data segment, or if we lack a data segment, it // can't be less than the end of the code segment. // also, always zero up to the end of the last page, even if the // segment ends sooner (otherwise expose old data to the process). segStart = noffH->uninitData.virtualAddr; segStart = max(segStart, noffH->initData.virtualAddr+noffH->initData.size); segStart = max(segStart, noffH->code.virtualAddr+noffH->code.size); segEnd = segStart + noffH->uninitData.size + UserStackSize; segEnd += (segEnd % PageSize) ? PageSize - (segEnd % PageSize) : 0; //round if (pageEnd > segStart && pageStart < segEnd) { offset = max(0, segStart - pageStart); len = PageSize - offset - max(0, pageEnd - segEnd); ASSERT(0 <= offset && offset <= PageSize); ASSERT(0 <= len && len <= PageSize); ASSERT(offset/PageSize == (offset+len-1)/PageSize); // all same page DEBUG('A', "LoadPage: zero vpn=%d, off=%d, len=%d\n", vpn, offset, len); bzero(&machine->mainMemory[pagePhys+offset], len); } // now that the page is loaded, set the pageTable state. pageTable[vpn].valid = TRUE; pageTable[vpn].use = FALSE; pageTable[vpn].dirty = FALSE; // if this page is exclusively code segment, mark it read only. if (pageStart >= noffH->code.virtualAddr && pageEnd <= noffH->code.virtualAddr + noffH->code.size) pageTable[vpn].readOnly = TRUE; else pageTable[vpn].readOnly = FALSE; }