# Nachos HK1
### 新增 page 紀錄 非自創參考


用 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

```
class AddrSpace {
public:
static bool recordedPhyPage[NumPhysPages];
// Edit by User wang
// record memory page in physicalPage
}
```
### 宣告

```
#include "copyright.h"
#include "main.h"
#include "addrspace.h"
#include "machine.h"
#include "noff.h"
bool AddrSpace::recordedPhyPage[NumPhysPages] = {0};
```
### 計算 page

```
// 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;
}
```
### 完成後編譯

```
wang@ubuntu:~/Nachos/nachos-4.0/code/userprog$ make
```

```
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


```
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
```

### 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

首先呼叫usrprogram的 "syscall.h"
```
#include "syscall.h"
```


這裡可以讓 program 知道 Halt() 已經存在被定義過
沒有定義過的 fun 不能被呼叫
再來進入主程式 main() 檔案位在 bin 資料夾
內部的 argc argv 則是針對在 cmd 內傳入的參數做讀取

設定 Break point 在


這部分可以看到當要執行 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 來決定要執行哪個項目

### 這部分負責執行讓 Nachos 能夠執行 User 程式將 kernal 的狀態由系統模式改為使用者模式

### 主要用來執行 User Program 包括處理異常、中斷和系統呼叫

### Find at ../machine/mipssim.cc:558

### 執行 RaiseException

```
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
}
```