# Nachos HK1 ### 新增 page 紀錄 非自創參考 ![](https://hackmd.io/_uploads/S1HJ7DtW6.png) ![](https://hackmd.io/_uploads/rkPwmPt-6.png) 用 break poin 追蹤執行順序 ``` Breakpoint 2, AddrSpace::AddrSpace (this=0x8069420) at ../userprog/addrspace.cc:56 Breakpoint 5, AddrSpace::Execute (this=0x8069420, fileName=0xbffff2cc "../test/test1") at ../userprog/addrspace.cc:156 156 if (!Load(fileName)) { Breakpoint 3, AddrSpace::Load (this=0x8069420, fileName=0xbffff2cc "../test/test1") at ../userprog/addrspace.cc:95 95 { Breakpoint 6, AddrSpace::InitRegisters (this=0x8069420) at ../userprog/addrspace.cc:186 186 Machine *machine = kernel->machine; Breakpoint 7, AddrSpace::RestoreState (this=0x8069420) at ../userprog/addrspace.cc:230 230 kernel->machine->pageTable = pageTable; ``` At : addespace.h ![](https://hackmd.io/_uploads/ByUZz1l-p.png) ``` class AddrSpace { public: static bool recordedPhyPage[NumPhysPages]; // Edit by User wang // record memory page in physicalPage } ``` ### 宣告 ![](https://hackmd.io/_uploads/SkZdmJe-p.png) ``` #include "copyright.h" #include "main.h" #include "addrspace.h" #include "machine.h" #include "noff.h" bool AddrSpace::recordedPhyPage[NumPhysPages] = {0}; ``` ### 計算 page ![](https://hackmd.io/_uploads/S16bmXlbT.png) ``` // Edit by User wang // morris add pageTable = new TranslationEntry[numPages]; for(unsigned int i = 0, j = 0; i < numPages; i++) { pageTable[i].virtualPage = i; while(j < NumPhysPages && AddrSpace::recordedPhyPage[j] == true) j++; AddrSpace::recordedPhyPage[j] = true; pageTable[i].physicalPage = j; pageTable[i].valid = true; pageTable[i].use = false; pageTable[i].dirty = false; pageTable[i].readOnly = false; } // end morris add ``` ### 在執行結束後清空 At : bool AddrSpace::Load(char *fileName) ``` AddrSpace::~AddrSpace() { for(int i = 0; i < numPages; i++) AddrSpace::recordedPhyPage[pageTable[i].physicalPage] = false; // Edit by User wang // free and reset delete pageTable; } ``` ### 完成後編譯 ![](https://hackmd.io/_uploads/BkMeErlZa.png) ``` wang@ubuntu:~/Nachos/nachos-4.0/code/userprog$ make ``` ![](https://hackmd.io/_uploads/HJzDwrgbT.png) ``` wang@ubuntu:~/Nachos/nachos-4.0/code/userprog$ ./nachos -e ../test/test1 -e ../test/test2 Total threads number is 2 Thread ../test/test1 is executing. Thread ../test/test2 is executing. Print integer:9 Print integer:8 Print integer:7 Print integer:20 Print integer:21 Print integer:22 Print integer:23 Print integer:24 Print integer:6 Machine halting! Ticks: total 239, idle 0, system 60, user 179 Disk I/O: reads 0, writes 0 Console I/O: reads 0, writes 0 Paging: faults 0 Network I/O: packets received 0, sent 0 Assertion failed: line 57 file ../lib/list.cc Aborted (core dumped) ``` ## Trace code 2 ![](https://hackmd.io/_uploads/Byef6uSZT.png) ![](https://hackmd.io/_uploads/B1DiaOHZp.png) ``` gdb-peda$ b Machine::Run Breakpoint 2 at 0x8056405: file ../machine/mipssim.cc, line 54. gdb-peda$ info b Num Type Disp Enb Address What 2 breakpoint keep y 0x08056405 in Machine::Run() at ../machine/mipssim.cc:54 ``` ![](https://hackmd.io/_uploads/HyIuzFBbp.png) ### void Machine::Run() 開始執行 User 程式碼,模擬在Nachos上運行的用戶級程序的執行,使用for loop 不回傳持續執行 假如運行的時間已達到指定的時間 runUntilTime 會呼叫 Debugger ### void Machine::OneInstruction(Instruction *instr) 執行用戶指令, //---------------------------------------------------------------------- // Machine::OneInstruction // Execute one instruction from a user-level program // // If there is any kind of exception or interrupt, we invoke the // exception handler, and when it returns, we return to Run(), which // will re-invoke us in a loop. This allows us to // re-start the instruction execution from the beginning, in // case any of our state has changed. On a syscall, // the OS software must increment the PC so execution begins // at the instruction immediately after the syscall. // // This routine is re-entrant, in that it can be called multiple // times concurrently -- one for each thread executing user code. // We get re-entrancy by never caching any data -- we always re-start the // simulation from scratch each time we are called (or after trapping // back to the Nachos kernel on an exception or interrupt), and we always // store all data back to the machine registers and memory before // leaving. This allows the Nachos kernel to control our behavior // by controlling the contents of memory, the translation table, // and the register set. //---------------------------------------------------------------------- ``` wang@ubuntu:~/Nachos/nachos-4.0/code/userprog$ gdb ./nachos -q Reading symbols from ./nachos...done. gdb-peda$ b Interrupt::Halt Breakpoint 1 at 0x804d3a5: file ../machine/interrupt.cc, line 236. gdb-peda$ ``` ``` Breakpoint 1, Interrupt::Halt (this=0x8067ad0) at ../machine/interrupt.cc:236 236 cout << "Machine halting!\n\n"; 237 kernel->stats->Print(); 238 delete kernel; // Never returns. ``` ``` Breakpoint 2, Interrupt::Idle (this=0x8067ad0) at ../machine/interrupt.cc:210 210 DEBUG(dbgInt, "Machine idling; checking for interrupts."); gdb-peda$ list 211 , 214 211 status = IdleMode; 212 if (CheckIfDue(TRUE)) { // check for any pending interrupts 213 status = SystemMode; 214 return; // return in case there's now ``` ``` void Interrupt::Idle() { DEBUG(dbgInt, "Machine idling; checking for interrupts."); status = IdleMode; if (CheckIfDue(TRUE)) { // check for any pending interrupts status = SystemMode; return; // return in case there's now // a runnable thread } // if there are no pending interrupts, and nothing is on the ready // queue, it is time to stop. If the console or the network is // operating, there are *always* pending interrupts, so this code // is not reached. Instead, the halt must be invoked by the user program. DEBUG(dbgInt, "Machine idle. No interrupts to do."); cout << "No threads ready or runnable, and no pending interrupts.\n"; cout << "Assuming the program completed.\n"; Halt(); } ``` void Interrupt::Idle() Routine called when there is nothing in the ready queue. bool Debug::IsEnabled(char flag) Return TRUE if DEBUG messages with "flag" are to be printed. int main(int argc, char **argv) Bootstrap the operating system kernel void Interrupt::Schedule(CallBackObj *toCall, int fromNow, IntType type) Arrange for the CPU to be interrupted when simulated time reaches "now + when". Timer::SetInterrupt Timer::Timer Alarm::Alarm ThreadedKernel::Initialize currentThread->setStatus(RUNNING) interrupt->Enable(); Debug::IsEnabled Interrupt::ChangeLevel Interrupt::OneTick Interrupt::OneTick # HK01-2 ![](https://hackmd.io/_uploads/rkzPlbYZ6.png) 首先呼叫usrprogram的 "syscall.h" ``` #include "syscall.h" ``` ![](https://hackmd.io/_uploads/HyYQ-btb6.png) ![](https://hackmd.io/_uploads/BkjrZ-Y-p.png) 這裡可以讓 program 知道 Halt() 已經存在被定義過 沒有定義過的 fun 不能被呼叫 再來進入主程式 main() 檔案位在 bin 資料夾 內部的 argc argv 則是針對在 cmd 內傳入的參數做讀取 ![](https://hackmd.io/_uploads/BJDpGWKZp.png) 設定 Break point 在 ![](https://hackmd.io/_uploads/HypambtWa.png) ![](https://hackmd.io/_uploads/rJdVNWtba.png) 這部分可以看到當要執行 Halt 時 CPU 會被打斷並要準備執行 ``` #0 Interrupt::Halt (this=0x8067ad0) at ../machine/interrupt.cc:236 #1 0x08055020 in ExceptionHandler (which=SyscallException) at ../userprog/exception.cc:62 #2 0x08055e4f in Machine::RaiseException (this=0x8067d58, which=SyscallException, badVAddr=0x0) at ../machine/machine.cc:109 #3 0x08057fb2 in Machine::OneInstruction (this=0x8067d58, instr=0x806d5c0) at ../machine/mipssim.cc:558 #4 0x080564c4 in Machine::Run (this=0x8067d58) at ../machine/mipssim.cc:62 #5 0x08054cee in AddrSpace::Execute (this=0x8069420, fileName=0xbffff2cd "../test/halt") at ../userprog/addrspace.cc:183 #6 0x08059264 in ForkExecute (t=0x8069238) at ../userprog/userkernel.cc:88 #7 0x0805a2c6 in ThreadRoot () #8 0x0805a2be in ?? () ``` ### 剛剛可以在 "syscall.h" 內看到 SC_Halt 對應的數字為 0 利用 switch 來決定要執行哪個項目 ![](https://hackmd.io/_uploads/HJCG8WYb6.png) ### 這部分負責執行讓 Nachos 能夠執行 User 程式將 kernal 的狀態由系統模式改為使用者模式 ![](https://hackmd.io/_uploads/rkeoTwWKba.png) ### 主要用來執行 User Program 包括處理異常、中斷和系統呼叫 ![](https://hackmd.io/_uploads/S1f3oZFbp.png) ### Find at ../machine/mipssim.cc:558 ![](https://hackmd.io/_uploads/Bkmcj-Kb6.png) ### 執行 RaiseException ![](https://hackmd.io/_uploads/Hyc3JMtba.png) ``` bool AddrSpace::Load(char *fileName) { OpenFile *executable = kernel->fileSystem->Open(fileName); NoffHeader noffH; unsigned int size; if (executable == NULL) { cerr << "Unable to open file " << fileName << "\n"; return FALSE; } executable->ReadAt((char *)&noffH, sizeof(noffH), 0); if ((noffH.noffMagic != NOFFMAGIC) && (WordToHost(noffH.noffMagic) == NOFFMAGIC)) SwapHeader(&noffH); ASSERT(noffH.noffMagic == NOFFMAGIC); // how big is address space? size = noffH.code.size + noffH.initData.size + noffH.uninitData.size + UserStackSize; // we need to increase the size // to leave room for the stack numPages = divRoundUp(size, PageSize); // cout << "number of pages of " << fileName<< " is "<<numPages<<endl; size = numPages * PageSize; ASSERT(numPages <= NumPhysPages); // check we're not trying // to run anything too big -- // at least until we have // virtual memory DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size); // then, copy in the code and data segments into memory if (noffH.code.size > 0) { DEBUG(dbgAddr, "Initializing code segment."); DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size); executable->ReadAt( &(kernel->machine->mainMemory[noffH.code.virtualAddr]), noffH.code.size, noffH.code.inFileAddr); } if (noffH.initData.size > 0) { DEBUG(dbgAddr, "Initializing data segment."); DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size); executable->ReadAt( &(kernel->machine->mainMemory[noffH.initData.virtualAddr]), noffH.initData.size, noffH.initData.inFileAddr); } delete executable; // close file return TRUE; // success } ```