nachos 。。。不認真版本

## 一些小話

? ? ? ? ? 前段時間因為一些雜七雜八的事情 被逼無奈 趕各種作業 再加上某個姓張的賤人 欺騙我說計網課設得交了 就一直把nachos的實驗放在一邊 然后今天聽朋友說操作系統沒做完 所以就想著按照自己的理解寫一個盡量傻瓜版的教程 試一試 看下能不能嘗試著寫的清晰一點 當作操作系統實驗報告了。。。(雖然每次都是做完實驗不寫報告。。期末再趕吧 希望不要被打死)


## 開始

寫實驗之前我們的看看我們要寫什么以及我們擁有什么 我們要做的其實就是用我們擁有技能去做我們要寫的東西 就ok了 所以先捋一捋

#### 我們要寫什么

我們要在一個叫做nachos的實驗代碼中去添加一段代碼 完成

訪問TLB

TLB調度算法

#### 我們擁有什么

有一份叫做nachos的實驗源碼

順手有了助教哥哥的ppt

會一點點c和c++(c++這一部分其實不太重要 如果后續的過程中需要用到的地方 我會給出教詳細的解釋 以及根據c的語法猜c++的語法)

會一點操作系統的理論(虛擬內存和TLB) ==> 這一部分我不太自信 下一節會給出說明 先忽略此條

會瞎猜東西 可以從搖擺人三個字猜出籃球上的搖擺人估計跑得賊快 得到處跑(雖然是玩笑 但我覺得很重要的一個技能 nachos的實驗源碼看完估計得一段時間 所以很多實現我們得根據函數名去猜)

一顆被其他代碼折磨過已經對世界絕望的心 反正我耐性好 賊好

好了 如果你也和我一樣無聊 擁有以上大多數 這篇教程大概能夠看懂了 哦 對了 還得忍受我逼逼 我給別人將東西習慣把別人當白癡 講的賊細 別無他法的時候 就先選我的試試吧。。

## go

兩個部分講解 理論+實驗 理論部分比較少 賊少 重點實驗

#### 理論

講理論有點糾結 因為我當時聽助教哥哥講了一大堆理論之后 有點方 這都啥啥啥 我的代碼在哪 但是不講理論部分 直接做實驗 又感覺大多數人ctrl+c 然后 ctrl+v就把實驗做完了 這是一件挺無聊的事 所以我想講下理論 不過會很短 這部分的理論可能還沒我現在講的這段話的字數多 這些理論可能是錯的 可能是模糊的 但能夠支撐這次實驗完成(原諒我 我也只是個學生) 具體的理論知識依靠 剛哥講解 + 操作系統教材 + google

理論:

我們先回到我們要寫什么 TLB

TLB的概念是因為什么^_^ 虛擬內存

虛擬內存是因為什么^_^ ? 物理內存

所以我們得到下面的公式:

TLB-->虛擬內存-->物理內存

我們只要搞懂這三個就ok

物理內存: 計算機你想一下 根據能量守恒原則(高中的時候我們學過 這只是一個類比 別當真)

有一天你要在計算機上面跑一個程序

你得放點能量讓程序運行

你運行的程序需要能量從哪里來

==> 操作系統提供了能量 wjl官方術語翻譯一下就是

操作系統讓程序跑起來

好了 仔細想想這句話 操作系統讓程序跑起來 emmm 那我們在哪里跑 是不是要占一個空間 在這臺電腦里面(電腦包含操作系統 操作系統包含程序) 這個程序具體運行在電腦的哪個ka ka guo guo? 就叫物理地址

虛擬內存:有一天我們相當不幸 選了一個禿頂的專業 學了c語言 開始寫程序 你的程序也得在某個地方跑起來 程序的數據得放在某一個位置 那你放的位置要是和另外一個程序放的位置一樣 不就很尷尬(別人有個b=1放在2處 你有一個a=3也想放在2這個地方 就覆蓋了 所以你破壞了別人辛辛苦苦的變量b 就很尷尬 ok) 假設每個程序員寫程序的時候都得去考慮其他人寫的程序的數據放哪 這事兒賊惡心了 估計得忙死一大波人 作為一位優秀的程序員 我們都是優秀的甩鍋俠 所以程序數據的位置的尷尬我們交給操作系統的設計者背鍋 設想一種幸福的情況

我有一個程序A 別人有一個程序B 假設我們可以幸福的認為

A占領位置:0-30

B占領位置:0-30

A::0-30和B::0-30? ? 這兩個是不同的空間 A永遠影響不了B B也不關A鳥事 這是一件多么幸福的事呀 這就叫做虛擬內存

至于他們為什么看起來數值相同 但空間不同 就得看操作系統設計者那群背鍋俠的實現了 不過可以假設操作系統(為了方便 用C代替)總共擁有0-30的空間 定義A::2 = C::6, B::2 = C::7(這個定義其實就是虛擬地址轉物理地址) 這樣就可以實現數據位置的看起來相同 但實際上物理地址不同 至于為什么30的空間可以裝下60(A:30 + B:30 = 60)這就是操作系統的調度 一段時間內放AB的片段((A的片段 < 30 + B的片段<30) <= 30 滿足這個條件即可) 這是另外一個問題了

那操作系統怎么來轉換A::2 = C::6 呢 有一種叫做頁表的結構 片段這玩意太不專業了 所以我們用頁的概念來代替 根據上面 假設A有10個片段 即為A有10頁 每頁的起始地址不一樣 定義前三頁 我們記作A1, A2, A3 stAddr:代表頁起始地址 A1_stAddr = 1000, A2_stAddr = 2000, A3_stAddr = 3000, 數據項物理地址A_data_1=1001 A_data_2=2001 A_data_3=3001,? ? 我們現在先規定一個數組virTable={11, 21,31} 這里面放的A_data_1, A_data_2, A_data_3的虛擬地址? 有一個數組叫做pageTable={10,20,30} 叫做頁表 我們怎么根據virTable, pageTable來找數據的物理地址呢

開始我們的表演

先找virTable 獲取11 規定第一位為頁表項 1 第二位為offset(偏移地址) 1 根據頁表項找到起始地址 對應pageTable[0] 為10 執行加法10 * 100(100代表pageFrame)+1 = 1001 還是有丟丟神奇 我們找到他了 1001 就是物理地址 11是虛擬地址

TLB: 那pageTable放哪呀 哥 這個呢 放一個寄存器里面就太好了 但是你一想 寄存器可賊貴了 而且前面我是比較樂觀 A賊小 假設你用java(好吧 我在黑java)寫了一個程序 那程序又臭又長 還賊慢 一共1000000MB 那你得分100000頁( 假設) 我們的pageTable得記錄100000個數據 是不是發現寄存器不夠了 所以我們把他放在內存里(內存 賊大 真的 放個頁表那絕對夠)

stop

停下來之后想一想 我們有100000個頁表項 假設每個訪問一次 執行cpu->內存100000次 這個過程呢 就有點慢 因為內存便宜嘛 你什么時候見過便宜的東西跑得賊快的 (比如java女裝程序員就賊便宜 那程序速度..) 所以我們能不呢讓他快一點呢 這個時候TLB就上場了 我們放一部分頁表項在TLB里面 這樣TLB里面有頁表項的時候 直接訪問TLB獲取起始地址就可以了

TLB這種東西 總結來說 就是訪問TLB比寄存器慢 但比內存快 價格比寄存器便宜 但比內存貴

所以這種人和稀泥就賊合適

速度(cpu->TLB->get起始地址*100000) > 速度(cpu->內存->get起始地址* 100000)==>重要公式A

記住這個公式A 我們程序的實現就是這個公式A

TLB是一個中轉(理解這個)

#### 和nachos相關的理論總結

程序由頁表進行虛擬地址向物理地址的轉換(cpu->mem) 源代碼已經實現

程序為了提高 放了一個緩沖器TLB(此處存放一部分頁表項) 分為以下兩種情況

if(訪問頁表項在TLB中)

get起始地址

else

進行cpu->內存->get起始地址的訪問

程序原來未實現TLB進行的訪問是

進行cpu->內存->get起始地址的訪問

####實驗

很抱歉我BB了那么久 我們來講實驗吧 怎么轉換代碼

注意看我們理論總結 TLB else的地方 與第三點程序原來未實現TLB的訪問 你會發現他們簡直一摸一樣 都是? ? ? ? ? 進行cpu->內存->get起始地址的訪問

原來的程序是可以運行的 所以我們可以推測 "進行cpu->內存->get起始地址的訪問"

這個機制在源代碼中已經實現了 那就意味著 我們只要把原有的代碼復制粘貼到想要的地方就可以了(請記住這個觀點)

所以 原有的代碼段在哪找 所以我們得找到mem的實現 在這個地方插入TLB 那怎么找呢?

不用擔心 我們已經幫你找好了

先介紹這個 nachos的文件夾結構 從code目錄開始

在寫程序的過程中 我們得時刻查閱自己寫的對不對 就得把有關虛擬內存的部分顯示出來 如何顯示呢

好了 現在假設我們的實驗文件已經完成 我們所需要的命令是nachos -x ../test/add.noff -d a(在build.linux 下輸入這個)

那么 -x -d a 這三個參數是怎么回事

-x: 在/threads/main.cc 里面的main函數里面 實現了-x的解析 代表如果-x出現 加載-x后的參數 ../test/add.noff 賦值給userProgName 作為為用戶程序 讓用戶程序在nachos里面運行

-d | -a 在lib/debug.h 里面 實現了一個加做DEBUG的宏 在調試模式下 會輸出各種調試信息

-d(main.cc 解析) 開啟調試模式

-a代表輸出有關虛擬內存的分配(建議查看注釋 都有詳細的解釋 22到26行)

好了 我們開始正題 尋找"原有的代碼段" 首先發現 -x獲取之后 得到userProgName 然后在后續的過程中 調用space->Execute() 程序將會一直執行下去(main.cc)

space從哪里來 打開userProg/Addrspace.h? 發現定義了AddrSpace這個類 在.cc文件里面實現了Execute();? ==>AddrSpace.cc

為了方便 我直接寫出函數代碼調用流程

space->Execute() ==> kernel->machine->Run() ==>OneInstruction(instr); ==>/

stop

OneInstruction(instr); 這個東西是 每次執行一條指令 假設程序有50條指令 一條一條執行就可以把程序跑完 這就叫關鍵函數1

繼續

OneInstruction(instr);==>ReadMem(registers[PCReg], 4, &raw)

進入關鍵函數1細看 發現先經過ReadMem讀取用戶指令的值 獲取指令的值放入raw中 根據raw的值不同 執行不同的操作 比如raw = 123(1 23)計算2+3 raw=223(2 23) 計算2-3 2叫做操作碼(opcode) 23叫做操作數(這里的定義十分不準確 先這樣理解著)

我們的指令放到一個地方 根據前面 這個地方我們現在擁有的是虛擬地址 4看起來應該是地址長度 那么register[PCReg]應該就是虛擬地址存放地點了 ReadMem記作關鍵函數2

繼續

Machine::ReadMem(int addr, int size, int *value)

這是ReadMem原型 addr為虛擬地址 value為取值

ReadMem==>Translate() 將虛擬地址轉化為物理地址 獲取raw的值 放入value當中

注意這里的代碼段

exception = Translate(addr, &physicalAddress, size, FALSE);

? if (exception != NoException)

{

RaiseException(exception, addr);

return FALSE;

? }

exception檢驗取值過程是否出錯 若沒有出錯 程序繼續運行 如果錯了 返回異常 退出程序

后面的switch語句? 根據size的值? 獲取value的值? 然后給raw 比如地址為1234 放了值11 00 11 00 如果size = 1 取得 value = 11(11為8-bit 1byte) 若size = 3 value = 11 00 11(忽視小端序大端序的問題)

所以Translate執行的就是由虛擬地址轉換物理地址 起始從參數名也可以看出(請查看Translate的參數名 函數原型)

addr: 虛擬地址

physvalue 代表物理地址

這是very關鍵函數3 我們的原有的代碼段就是在這里進行的

繼續

進入Translate函數查看流程 根據我們以前的公式

此處標記為過程AAAA

1001

獲取頁表項序號(1): vpn = (unsigned) virtAddr / PageSize;

翻譯一下 1 = 11 / 10

? ? 獲取 offset = (unsigned) virtAddr % PageSize;

翻譯一下 1 = 11 % 10

獲取起始地址: pageFrame = entry->physicalPage;

翻譯一下: 100 = PageTable[0]

獲取物理地址 *physAddr = pageFrame * PageSize + offset;

翻譯一下? 1001 = 100 * 10 + 1(這里和我前面講的理論有點出入 湊合著理解吧 我才20歲 我想睡覺)

從PageFrame那里開始的地方 就是頁表轉換的過程

代碼如下

pageFrame = entry->physicalPage;==>從這里開始一直到Translate結束 就是 "原程序代碼"

我們要做的 根據前面所說 起始就是把這段代碼復制粘貼到合適的地方

那么 哪兒是合適的地方呢

讓我們來看看我們的TLB TLB中的 if else指出 如果PageTable[i]在TLB里面 通過TLB訪問PageTable[i] 如果不存在 就通過PageTable的表直接訪問 對應代碼下

for (entry = NULL, i = 0; i < TLBSize; i++)

? ? ? ? if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {

entry = &tlb[i]; // FOUND!

break;

? }

if (entry == NULL) { // not found

? ? ? ? DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");

? ? ? ? return PageFaultException; // really, this is a TLB fault,

for循環里面進行了TLB的遍歷 如果存在 就直接獲取頁表項 然后獲取起始地址 進行轉換 如果不存在 拋出PageFaultException異常 (根據我們前面if else的說法 叫做繼續通過頁表訪問 頁表訪問原來是由過程AAAA進行的處理 但是現在我們已經return PageFaultException;出函數體了 過程AAAA無法執行 所以程序在打開TLB選項如果這樣運行 沒人幫忙擦屁股 就無法處理頁表項不在TLB中的情況 就會出錯) 所以 我們的初級任務達成

任務1:當頁表項不在TLB中 模仿原有的程序代碼 實現一個新的CPU->TLB->get起始地址(在return pageFaultException;之后實現)

小貼士:

我們要寫的代碼其實不多 既然叫模仿 其實復制粘貼就可以了

程序這里寫參數bug 活用ASSERTNOTREACED()調試程序

#### 開始模仿

wait 模仿啥 仔細想想 我們應該是模仿在 TLB 調用 在TLB中找不到表項之后 模仿擦屁股的過程 那么 關鍵字 TLB

emmmm TLB 這玩意 存在么

這個問題等同于

原有的關鍵機制 PagetTable在源代碼中 對應的是變量名PageTable

TLB在源碼用對應一個變量名叫做tlb的結構體

在Translate函數當中中 有一段

if tlb == null

do something

else

do tlb something

do something這一段使用原有的PageTable的調用 而程序為了能夠運行 在未實現TLB的時候 程序保證tlb永遠為null 所以我們得先弄明白

為什么在原來給出的源碼當中 TLB會默認被保證為null呢

這一段的代碼體現在

#ifdef USE_TLB (/machine/machine.cc中可見這段代碼)

? ? tlb = new TranslationEntry[TLBSize];

? ? for (i = 0; i < TLBSize; i++)

tlb[i].valid = FALSE;

? ? pageTable = NULL;

#else // use linear page table

? ? tlb = NULL;

? ? pageTable = NULL;

#endif

至于這一段 得先理解ifdef USE_TLB語句 這句話擴充一下就是

if USE_TLB define

等效于

如果USE_TLB定義過 則編譯ifdef代碼塊 否則編譯else處代碼塊 所以我們得先讓tlb != null定 那么我們得定義USE_TLB

#define USE_TLB

放一下這個語句在machine.h 的第一行 然后對nachos進行make 進行我們要輸入的命令 得到結果如圖

程序出錯了 謝天謝地 出錯是好事 你想 我們把TLB選項打開了 擦屁股的事沒有干 不出錯才有鬼 那么 為什么會出錯

看一下201 行 得到如圖

ASSERT 什么鬼

這個的定義在lib/debug.h里面 總結來說 ASSERT是這樣一個函數

ASSERT(條件A): 如果條件A為真 程序啥事都沒有 如果條件A為假 程序退出 并且打印出ASSERT在程序的哪一行 當前在201(translate.cc)行

// we must have either a TLB or a page table, but not both!

? ? ASSERT(tlb == NULL || pageTable == NULL);

? ASSERT(tlb != NULL || pageTable != NULL);

再來看下程序注釋 我的詞匯量為500的翻譯就是? TLB和PageTable有且只有一個(有的意思是指不為NULL)

舉例 TLB = NULL PageTable == NULL 程序 202不滿足 出錯

TLB != NULL PageTable != NULL 201不滿足 出錯

我們打印一下TLB和PageTable的值 添加以下代碼

221? ? #ifdef USE_TLB

222? ? ASSERT(tlb != NULL && pageTable != NULL);

223? ? #else

224? ? std::cout << "TLB " << tlb << "PageTable " << pageTable << std::endl;

225? ? ASSERT(tlb == NULL || pageTable == NULL);

226? ? ASSERT(tlb != NULL || pageTable != NULL);

227? ? #endif

make 然后繼續運行 效果如圖

程序繼續出錯 做到這里我覺得我們可以哭了 Invalid TLB emmm 說明我們的TLB的已經見效了 只是我們的算法沒有實現 沒有在TLB里面找到表項而已 我們處理完就萬事OK了

wait 沒有在TLB里面找到表項。。。啥意思 我們根據前面講的

TLB比較貴 放不下所有頁表 所以我們只是放了一部分

舉個例子 程序A有 1 2 3 4 5 TLB含有 1 2 表項 當查找2 的時候 在for循環里面遍歷能找到表項 直接獲取值 對應代碼(查看translate函數)在這

for (entry = NULL, i = 0; i < TLBSize; i++)

if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {

entry = &tlb[i]; // FOUND!

break;

}

entry獲取值 然后進行虛擬地址到物理地址的運算

然后我們查看源代碼 如果不在tlb中 發現拋出異常 實現如下

return pageFaultException

還記得translate是由ReadMem調用 所以這個pageFaultException的值會返回給ReadMem

查看ReadMem 發現如下(查看ReadMem函數)

if (exception != NoException) {

RaiseException(exception, addr);

return FALSE;

}

顯然我們返回的是pageFaultException 不等于noException 程序轉而調用RaiseException 查看RaiseException 發現程序繼續調用ExceptionHandler()

在userprog/exception.cc 找到ExceptionHandler函數 結合錯誤信息 找到出錯的那一行 ASSERTNOTREACHED()? ==> 108 行 這里程序終止

對ASSERTTHREAD進行小小的解釋 大概可以理解為 程序只要運行到這就會報錯退出(見debug.h查看實現) 那為什么要有這個函數呢 因為程序有些地方按正常的流程絕對不應該運行到這 這樣的話會打印行數 方便我們調試 解釋這么多是因為后面我們調試bug的時候需要用到

為什么會運行到108行 因為沒有對pageFaultException進行處理(查看switch語句可以發現 根本沒有 case pageFaultException:)

那我們對這進行一下美化(在switch(which)下面一行添加) 代碼如下:

case PageFaultException:

60? ? ? ? kernel->machine->ourHandleTLB();

61? ? ? ? return ;

62? ? ? ? ASSERTNOTREACHED();

return ;==>

保證程序運行不會經過ASSERTNOTREACHED()

重新編譯 運行 可以得到一個無限循環 如圖

這是因為總有拋出異常后我們并沒有對異常進行處理 沒有去取物理地址之類的 我們并沒有對這進行處理

分析一下 程序執行完return ;返回RaiseException中 然后返回到ReadMem 返回false 程序其實啥都沒做 所以我們對程序進行一下處理 即對TLB不在的情況進行處理

在return;前面加上 kernnel->machine->ourHandleTLB(); kernel對象會調用==>machine對象然后去調用屬于==>machine對象的一個叫做ourHanleTLB()的函數 然后我們在ourHandleTLB對象里面進行擦屁股就行了

ourHanleTLB是我們自己定義的 所以我們得自己實現 現在machine.h里面加入

void ourHanleTLB() --> 放在public下面

然后在translate里面實現 代碼如圖

void Machine::ourHandleTLB()

259 {

260

261? ? entry = &pageTable[vpn];

262

263? ? if (entry->readOnly && writing) {? // trying to write to a read-only page

264? ? ? ? DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);

265? ? ? ? return ReadOnlyException;

266? ? }

267? ? pageFrame = entry->physicalPage;

268

269? ? // if the pageFrame is too big, there is something really wrong!

270? ? // An invalid translation was loaded into the page table or TLB.

271? ? if (pageFrame >= NumPhysPages) {

272? ? ? ? DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);

273? ? ? ? return BusErrorException;

274? ? }

275? ? entry->use = TRUE;? ? ? ? ? // set the use, dirty bits

276? ? if (writing)

277? ? ? ? entry->dirty = TRUE;

278? ? *physAddr = pageFrame * PageSize + offset;

279? ? ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));

280? ? DEBUG(dbgAddr, "phys addr = " << *physAddr);

281? ? return NoException;

282 }

對比一下translate函數 你會發現簡直一摸一樣 因為我一早就說 他們做的事差不多 然后我們運行一下 得到結果如下

開始報錯 size等等沒有定義 為什么沒有定義 因為我們在這個函數體里面根本沒有實現size的聲明 就像憑空出現的一樣 所以我們得定義他

wait size這些 原來的值是和虛擬內存關聯的 現在我們需要虛擬內存的值 但是ourHandleTLB的函數體里面 參數部分未傳入這些必要的值 那我們怎么獲取呢

采用全局變量 把size等等設置為全局變量 如下 這就是我們要保存的變量的類型聲明 namespace稍后解釋

namespace USE_TLB_NAME

67 {

68? ? int i;

69? ? unsigned int vpn, offset;

70? ? TranslationEntry *entry;

71? ? unsigned int pageFrame;

72

74? ? int virtAddr, * physAddr,? size;

75? ? bool writing;

78 }

接下來是賦值(在if(tlb == NULL 添加USE_TLB_NAME代碼)) 把原來的值保存下來 如圖 修改后的結果如圖

USE_TLB_NAME::vpn = vpn;

235? ? USE_TLB_NAME::offset = offset;

236? ? USE_TLB_NAME::physAddr = physAddr;

237? ? USE_TLB_NAME::writing = writing;

238? ? USE_TLB_NAME::size = size;

239? ? USE_TLB_NAME::virtAddr = virtAddr;

240

241? ? if (tlb == NULL) {? ? ? ? ? // => page table => vpn is index into table

對不起 剛才有一段關鍵代碼未貼 更改ourHandleException()如下

void Machine::ourHandleTLB()

286 {

287

288? ? TranslationEntry *entry;

289? ? unsigned int pageFrame;

290

291? ? entry = &pageTable[USE_TLB_NAME::vpn];

292

293? ? if (entry->readOnly && USE_TLB_NAME::writing) {? ? // trying to write to a read-only page

294? ? ? ? DEBUG(dbgAddr, "Write to read-only page at " << USE_TLB_NAME::virtAddr);

295? ? ? ? return ReadOnlyException;

296? ? }

297? ? pageFrame = entry->physicalPage;

298

299? ? // if the pageFrame is too big, there is something really wrong!

300? ? // An invalid translation was loaded into the page table or TLB.

301? ? if (pageFrame >= NumPhysPages) {

302? ? ? ? DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);

303? ? ? ? return BusErrorException;

304? ? }

305? ? entry->use = TRUE;? ? ? ? ? // set the use, dirty bits

306? ? if (USE_TLB_NAME::writing)

307? ? ? ? entry->dirty = TRUE;

308? ? *USE_TLB_NAME::physAddr = pageFrame * PageSize + USE_TLB_NAME::offset;

309? ? ASSERT((*USE_TLB_NAME::physAddr >= 0) && ((*USE_TLB_NAME::physAddr + USE_TLB_NAME::size) <= MemorySize));

310? ? DEBUG(dbgAddr, "phys addr = " << *USE_TLB_NAME::physAddr);

311? ? flag = TRUE;

312? ? return NoException;

313 }

編譯運行程序

程序繼續報錯 讓我們來分析一下 程序陷入無限循環 處理完這個TLB的情況的時候 并沒有進行下一頁的處理 然后我們查看ReadMem函數處的調用? PageTableException返回的時候 程序已經正確處理了 但是返回的還是FALSE 所以報錯 讓我們處理一下這里

更改代碼 代碼如圖

exception = Translate(addr, &physicalAddress, size, TRUE);

163? ? if (exception != NoException) {

164? ? ? ? RaiseException(exception, addr);

165? ? ? ? if(flag == FALSE) // ok

166? ? ? ? ? ? ? ? return FALSE;

flag = FALSE;

167? ? }

程序加了if語句 flag是什么?

flag是我們定義的一個全局變量(在.translate.cc定義 bool flag = FALSE) 看下我們的TLB處理成功沒

如果成功 為TRUE

否則為默認值FALSE?

在ourHandler結尾粗 return Noexception之前一行處加上

flag = TRUE

所以如果返回TRUE 說明TLB處理完畢 不用管 繼續執行下面代碼 并把flag 重置為 FALSE 方便下一次檢驗

如果返回FALSE 程序return 程序失敗

實驗結果運行 我們發現 誒嘿 還是無限循環 不過這次要好多了 觀察value處 發現我們的實驗代碼可以取值了 只是取到某個值的時候 程序就崩了 那么。。我們來調試一下 gdb ? 抱歉哎完全不會 我們換個玩意 比如前面扯了一大隊的ASSERTNOTREACHED()-->讓程序終止 首先聲明一個全局變量int count = 0(取10是因為取10頁的次數 方便觀察)

在readMem加入如下代碼

? if(++count == 10) ASSERTNOTREACHED();

同flag一樣 count是一個全局變量 定義在文件開頭 10次之后停止

發現程序在負數

Invalid TLB entry for this virtual page!

phys addr = 388

value read = -1346437104

那里停下來 看一下正常流程應該是啥樣 去掉USE_TLB宏(注釋掉USE_TLB的定義 在Machine.h里面 ) 比對正常運行程序 發現是因為指令分為兩種模式 read write 沒有處理write函數 于是我們在writeMem里面加入和ReadMem相同的邏輯(加入前面的flag判斷) 去掉我們的調試程序 恢復USE_TLB宏定義 如圖

bingo 程序跑通了 完美 (不完美的地方還有很多 其實 比如pageTable在哪里賦予的值 我懶得寫了。。 tlb里面的頁表項是怎么放進去的 而且發現跑出來的結果全是INvalid tlb里里面根本沒有值 怎么賦值。。。 懶。。。)

stop at here

自己根據這個思路實現置換吧 反正都一樣 推薦FIFO算法 簡單

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,836評論 18 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,738評論 18 399
  • 五月的最后一天很喪。 無窮盡的孤獨和無助籠罩著我,每天很忙和很多人打交道,周旋在很多瑣事之間。我不知道如果換成別人...
    z二水閱讀 274評論 0 0
  • “媽!我回來啦” 每次回家,我都要懷疑一件事情 我可能回了一個“假家” 第一天 “回來啦,怎么穿這么少” “外面冷...
    王申斌閱讀 153評論 0 0
  • 利潤表是預估的概念,資產負債表是某一天定量的概念,現金流量表是一張生死攸關的報表。 現金流量表中,只要有任何現金流...
    ahamoment閱讀 193評論 0 0