---
# System prepended metadata

title: Nachos HK1

---

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

```