若使用網路下載usb安裝程式Download - Auto-installer for USB Key (Win 9x/2k/xp/7),製作完成後,開機執行出現測試程式畫面後有2~3秒的時間,若不按F2鍵,其實只是跑單核心程式,但是按F2執行多核程式,發現記憶體只要大於2GB,則到pattern7,block move便當掉了。若你會自行編譯,那就找出4.20版的source code,再比對和5.01版pattern7之間的差異,就可修正這個問題了。若你不執行多核程式測試,其實是沒有這個bug的。針對5.01版已經修完成DOS版本的.exe執行檔,並具備下參數功能,驗證沒有問題,找時間再來說如何實作了…
--> 閱讀更多...
2015年7月21日 星期二
2015年3月9日 星期一
Mint 17.1 32bits下compile memtest86+注意事項
不知道是否是linux kernel 版本號更新還是怎樣,當使用較新版的Mint進行compile memtets86+時,出現#include 找不到。
解決辦法:
sudo apt-get update && sudo apt-get install build-essential linux-headers-$(uname -r)
就搞定了!
另一個問題是,編譯時使用gcc 4.8.2產生的執行檔會當機,因此再使用Synapptic 進行安裝 gcc 4.4版,另外再將makefile :
CC=gcc改成CC=gcc-4.4,重新編譯,就可以了!
--> 閱讀更多...
解決辦法:
sudo apt-get update && sudo apt-get install build-essential linux-headers-$(uname -r)
就搞定了!
另一個問題是,編譯時使用gcc 4.8.2產生的執行檔會當機,因此再使用Synapptic 進行安裝 gcc 4.4版,另外再將makefile :
CC=gcc改成CC=gcc-4.4,重新編譯,就可以了!
2012年1月10日 星期二
BCB (Multi-thread)
轉載自http://96katt.blogspot.com/2010/09/bcb-multi-thread.html
單線程就是進程只有一個線程
多線程就是進程有多個線程!!!!
下面是多線程的例子
還在Dos時代,人們就在尋求一種多任務的實現。於是出現了TSR類型的後台駐留程序,比較有代表性的有Side Kick、Vsafe等優秀的TSR程序,這類程序的出現和應用確實給用戶使用計算機帶來了極大的方便,比如Side Kick,我們編程可以在不用進編輯程序的狀態下,一邊編輯源程序,一邊編譯運行,非常方便。但是,Dos單任務操作系統的致命缺陷注定了在Dos下不可 能開發出真正的多任務程序。進入Windows3.1時代,這種情況依然沒有根本的改變,一次應用只能做一件事。比如數據庫查詢,除非應用編得很好,在查 詢期間整個系統將不響應用戶的輸入。
進入了Windows NT和Windows 9x時代,情況就有了徹底的改觀,操作系統從真正意義上實現了多任務(嚴格地說,Win9x還算不上)。一個應用程序,在需要的時候可以有許多個執行線 程,每個線程就是一個小的執行程序,操作系統自動使各個線程共享CPU資源,確保任一線程都不能使系統死鎖。這樣,在編程的時候,可以把費時間的任務移到 後台,在前台用另一個線程接受用戶的輸入。對那些對實時性要求比較高的編程任務,如網絡客戶服務、串行通信等應用時,多線程的實現無疑大大地增強了程序的 可用性和穩固性。
在Windows NT和Windows 9x中,多線程的編程實現需要調用一系列的API函數,如CreateThread、ResumeThread等,比較麻煩而且容易出錯。我們使用 Inprise公司的新一代RAD開發工具C++Builder,可以方便地實現多線程的編程。與老牌RAD工具Visual Basic和Delphi比,C++Builer不僅功能非常強大,而且它的編程語言是C++,對於系統開發語言是C的Windows系列操作系統,它具 有其它編程語言無可比擬的優勢。利用C++Builder提供的TThread對象,多線程的編程變得非常簡便易用。那麼,如何實現呢?且待我慢慢道來, 讓你體會一下多線程的強大功能。
1. 創建多線程程序:
首先,先介紹一下實現多線程的具體步驟。在C++Builder中雖然用Tthread對像說明了線程的概念,但是Tthread對像本身並不完整, 需要在TThread下新建其子類,並重載Execute方法來使用線程對象。在C++Builder下可以很方便地實現這一點。
在C++Builder IDE環境下選擇菜單File|New,在New欄中選中Thread Object,按OK,接下來彈出輸入框,輸入TThread對像子類的名字MyThread,這樣C++Builder自動為你創建了一個名為 TMyThread的TThread子類。同時編輯器中多了一個名為Unit2.cpp的單元,這就是我們創建的TMyThread子類的原碼,如下:
#include
#pragma hdrstop
#include 「Unit2.h」
#pragma package(smart_init)
//────────────────────-
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall MyThread::UpdateCaption()
// {
// Form1->Caption = 「Updated in a thread」;
// }
//────────────────────
__fastcall MyThread::MyThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//────────────────────
void __fastcall MyThread::Execute()
{
//──── Place thread code here ────
}
//────────────────────-
其中的Execute()函數就是我們要在線程中實現的任務的代碼所在處。在原代碼中包含Unit2.cpp,這個由我們創建的TMyThread對象就可以使用了。使用時,動態創建一個TMyThread 對象,在構造函數中使用Resume()方法,那麼程序中就增加了一個新的我們自己定義的線程TMyThread,具體執行的代碼就是Execute()方法重載的代碼。要加載更多的線程,沒關係,只要繼續創建需要數量的TMyThread 對象就成。
以上我們初步地實現了在程序中創建一個自定義的線程,並使程序實現了多線程應用。但是,多線程應用的實現,並不是一件簡單的工作,還需要考慮很多使多 個線程能在系統中共存、互不影響的因素。比如,程序中公共變量的訪問、資源的分配,如果處理不當,不僅線程會死鎖陷入混亂,甚至可能會造成系統崩潰。總的 來講,在多線程編程中要注意共享對像和數據的處理,不能忽視。因此,下面我們要講的就是多線程中常見問題:
2. 多線程中VCL對象的使用
我們都知道,C++Builder編程是建立在VCL類庫的基礎上的。在程序中經常需要訪問VCL對象的屬性和方法。不幸的是,VCL類庫並不保證其 中對象的屬性和方法是線程訪問安全的(Thread_safe),訪問VCL對象的屬性或調用其方法可能會訪問到不被別的線程所保護的內存區域而產生錯 誤。因此,TThread對像提供了一個Synchronize方法,當需要在線程中訪問VCL對像屬性或調用方法時,通過Synchronize方法來 訪問屬性或調用方法就能避免衝突,使各個線程之間協調而不會產生意外的錯誤。如下所示:
void __fastcall TMyThread::PushTheButton(void)
{
Button1->Click();
}
void __fastcall TMyThread::Execute()
{
...
Synchronize((TThreadMethod)PushTheButton);
...
}
對Button1-〉Click()方法的調用就是通過Synchronize()方法來實現的,它可以自動避免發生多線程訪問衝突。在 C++Builder中,雖然有一些VCL對象也是線程訪問安全的(如TFont、TPen、TBrush等),可以不用Sychronize()方法對 它們的屬性方法進行訪問調用以提高程序性能,但是,對於更多的無法確定的VCL對象,還是強烈建議使用Synchronize()方法確保程序的可靠性。
3. 多線程中公共數據的使用
程序設計中難免要在多個線程中共享數據或者對象。為了避免在多線程中因為同時訪問了公共數據塊而造成災難性的後果,我們需要對公共數據塊進行保護,直 到一個線程對它的訪問結束為止。這可以通過臨界區域(Critical Section)的使用來實現,所幸的是在C++Builder中,給我們提供了一個TCriticalSection對像來進行臨界區域的劃定。該對像 有兩個方法,Acquire()和Release()。它設定的臨界區域可以保證一次只有一個線程對該區域進行訪問。如下例所示:
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
{
...
pLockX->Acquire();//Here pLockX is a Global CriticalSection variable.
x++;
y=sin(x);
pLockX->Release();
...
}
這樣,對公共變量x,y的訪問就通過全局TCriticalSection 對像保護起來,避免了多個線程同時訪問的衝突。
4. 多線程間的同步
當程序中多個線程同時運行,難免要遇到使用同一系統資源,或者一個線程的運行要依賴另一個線程的完成等等,這樣需要在線程間進行同步的問題。由於線程 同時運行,無法從程序本身來決定運行的先後快慢,使得線程的同步看起來很難實現。所幸的是Windows系統是多任務操作系統,系統內核為我們提供了事件 (Event)、Mutex、信號燈(semaphore)和計時器4種對像來控制線程間的同步。在C++Builder中,為我們提供了用於創建 Event的TEvent 對像供我們使用。
當程序中一個線程的運行要等待一項特定的操作的完成而不是等待一個特定的線程完成時,我們就可以很方便地用TEvent對像來實現這個目標。首先創建 一個全局的TEvent對像作為所有線程可監測的標誌。當一個線程完成某項特定的操作時,調用TEvent對象的SetEvent()方法,這樣將設置這 個標誌,其他的線程可以通過監測這個標誌獲知操作的完成。相反,要取消這個標誌,可以調用ResetEvent()方法。在需要等待操作完成的線程中使用 WaitFor()方法,將一直等待這個標誌被設置為止。注意WaitFor()方法的參數是等待標誌設置的時間,一般用INFINITE表示無限等待事 件的發生,如果其它線程運行有誤,很容易使這個線程死住(等待一個永不發生的事件)。
其實直接用Windows API函數也可以很方便地實現事件(Event)、信號燈(semaphore)控制技術。尤其是C++Builder,在調用Windows API方面有著其它語言無可比擬的優勢。所用的函數主要有:CreateSemaphore()、CreateEvent()、WaitForSingleObject()、ReleaseSemaphore()、SetEvent()等等,這裡就不贅述了。
本文結合Inprise(Borland)公司開發的強大的RAD工具C++Builder的編程,對Windows下的多線程編程作了比較全面的介紹。其實多線程的實現並不神秘,看了本文,你也可以編出自己的多線程程序,真正體會多任務操作系統的威力。
--> 閱讀更多...
單線程就是進程只有一個線程
多線程就是進程有多個線程!!!!
下面是多線程的例子
還在Dos時代,人們就在尋求一種多任務的實現。於是出現了TSR類型的後台駐留程序,比較有代表性的有Side Kick、Vsafe等優秀的TSR程序,這類程序的出現和應用確實給用戶使用計算機帶來了極大的方便,比如Side Kick,我們編程可以在不用進編輯程序的狀態下,一邊編輯源程序,一邊編譯運行,非常方便。但是,Dos單任務操作系統的致命缺陷注定了在Dos下不可 能開發出真正的多任務程序。進入Windows3.1時代,這種情況依然沒有根本的改變,一次應用只能做一件事。比如數據庫查詢,除非應用編得很好,在查 詢期間整個系統將不響應用戶的輸入。
進入了Windows NT和Windows 9x時代,情況就有了徹底的改觀,操作系統從真正意義上實現了多任務(嚴格地說,Win9x還算不上)。一個應用程序,在需要的時候可以有許多個執行線 程,每個線程就是一個小的執行程序,操作系統自動使各個線程共享CPU資源,確保任一線程都不能使系統死鎖。這樣,在編程的時候,可以把費時間的任務移到 後台,在前台用另一個線程接受用戶的輸入。對那些對實時性要求比較高的編程任務,如網絡客戶服務、串行通信等應用時,多線程的實現無疑大大地增強了程序的 可用性和穩固性。
在Windows NT和Windows 9x中,多線程的編程實現需要調用一系列的API函數,如CreateThread、ResumeThread等,比較麻煩而且容易出錯。我們使用 Inprise公司的新一代RAD開發工具C++Builder,可以方便地實現多線程的編程。與老牌RAD工具Visual Basic和Delphi比,C++Builer不僅功能非常強大,而且它的編程語言是C++,對於系統開發語言是C的Windows系列操作系統,它具 有其它編程語言無可比擬的優勢。利用C++Builder提供的TThread對象,多線程的編程變得非常簡便易用。那麼,如何實現呢?且待我慢慢道來, 讓你體會一下多線程的強大功能。
1. 創建多線程程序:
首先,先介紹一下實現多線程的具體步驟。在C++Builder中雖然用Tthread對像說明了線程的概念,但是Tthread對像本身並不完整, 需要在TThread下新建其子類,並重載Execute方法來使用線程對象。在C++Builder下可以很方便地實現這一點。
在C++Builder IDE環境下選擇菜單File|New,在New欄中選中Thread Object,按OK,接下來彈出輸入框,輸入TThread對像子類的名字MyThread,這樣C++Builder自動為你創建了一個名為 TMyThread的TThread子類。同時編輯器中多了一個名為Unit2.cpp的單元,這就是我們創建的TMyThread子類的原碼,如下:
#include
#pragma hdrstop
#include 「Unit2.h」
#pragma package(smart_init)
//────────────────────-
// Important: Methods and properties of objects in VCL can only be
// used in a method called using Synchronize, for example:
//
// Synchronize(UpdateCaption);
//
// where UpdateCaption could look like:
//
// void __fastcall MyThread::UpdateCaption()
// {
// Form1->Caption = 「Updated in a thread」;
// }
//────────────────────
__fastcall MyThread::MyThread(bool CreateSuspended)
: TThread(CreateSuspended)
{
}
//────────────────────
void __fastcall MyThread::Execute()
{
//──── Place thread code here ────
}
//────────────────────-
其中的Execute()函數就是我們要在線程中實現的任務的代碼所在處。在原代碼中包含Unit2.cpp,這個由我們創建的TMyThread對象就可以使用了。使用時,動態創建一個TMyThread 對象,在構造函數中使用Resume()方法,那麼程序中就增加了一個新的我們自己定義的線程TMyThread,具體執行的代碼就是Execute()方法重載的代碼。要加載更多的線程,沒關係,只要繼續創建需要數量的TMyThread 對象就成。
以上我們初步地實現了在程序中創建一個自定義的線程,並使程序實現了多線程應用。但是,多線程應用的實現,並不是一件簡單的工作,還需要考慮很多使多 個線程能在系統中共存、互不影響的因素。比如,程序中公共變量的訪問、資源的分配,如果處理不當,不僅線程會死鎖陷入混亂,甚至可能會造成系統崩潰。總的 來講,在多線程編程中要注意共享對像和數據的處理,不能忽視。因此,下面我們要講的就是多線程中常見問題:
2. 多線程中VCL對象的使用
我們都知道,C++Builder編程是建立在VCL類庫的基礎上的。在程序中經常需要訪問VCL對象的屬性和方法。不幸的是,VCL類庫並不保證其 中對象的屬性和方法是線程訪問安全的(Thread_safe),訪問VCL對象的屬性或調用其方法可能會訪問到不被別的線程所保護的內存區域而產生錯 誤。因此,TThread對像提供了一個Synchronize方法,當需要在線程中訪問VCL對像屬性或調用方法時,通過Synchronize方法來 訪問屬性或調用方法就能避免衝突,使各個線程之間協調而不會產生意外的錯誤。如下所示:
void __fastcall TMyThread::PushTheButton(void)
{
Button1->Click();
}
void __fastcall TMyThread::Execute()
{
...
Synchronize((TThreadMethod)PushTheButton);
...
}
對Button1-〉Click()方法的調用就是通過Synchronize()方法來實現的,它可以自動避免發生多線程訪問衝突。在 C++Builder中,雖然有一些VCL對象也是線程訪問安全的(如TFont、TPen、TBrush等),可以不用Sychronize()方法對 它們的屬性方法進行訪問調用以提高程序性能,但是,對於更多的無法確定的VCL對象,還是強烈建議使用Synchronize()方法確保程序的可靠性。
3. 多線程中公共數據的使用
程序設計中難免要在多個線程中共享數據或者對象。為了避免在多線程中因為同時訪問了公共數據塊而造成災難性的後果,我們需要對公共數據塊進行保護,直 到一個線程對它的訪問結束為止。這可以通過臨界區域(Critical Section)的使用來實現,所幸的是在C++Builder中,給我們提供了一個TCriticalSection對像來進行臨界區域的劃定。該對像 有兩個方法,Acquire()和Release()。它設定的臨界區域可以保證一次只有一個線程對該區域進行訪問。如下例所示:
class MyThread : public TThread
{
...
private:
TCriticalSection pLockX;
int x;
float y;
...
};
void __fastcall MyThread::Execute()
{
...
pLockX->Acquire();//Here pLockX is a Global CriticalSection variable.
x++;
y=sin(x);
pLockX->Release();
...
}
這樣,對公共變量x,y的訪問就通過全局TCriticalSection 對像保護起來,避免了多個線程同時訪問的衝突。
4. 多線程間的同步
當程序中多個線程同時運行,難免要遇到使用同一系統資源,或者一個線程的運行要依賴另一個線程的完成等等,這樣需要在線程間進行同步的問題。由於線程 同時運行,無法從程序本身來決定運行的先後快慢,使得線程的同步看起來很難實現。所幸的是Windows系統是多任務操作系統,系統內核為我們提供了事件 (Event)、Mutex、信號燈(semaphore)和計時器4種對像來控制線程間的同步。在C++Builder中,為我們提供了用於創建 Event的TEvent 對像供我們使用。
當程序中一個線程的運行要等待一項特定的操作的完成而不是等待一個特定的線程完成時,我們就可以很方便地用TEvent對像來實現這個目標。首先創建 一個全局的TEvent對像作為所有線程可監測的標誌。當一個線程完成某項特定的操作時,調用TEvent對象的SetEvent()方法,這樣將設置這 個標誌,其他的線程可以通過監測這個標誌獲知操作的完成。相反,要取消這個標誌,可以調用ResetEvent()方法。在需要等待操作完成的線程中使用 WaitFor()方法,將一直等待這個標誌被設置為止。注意WaitFor()方法的參數是等待標誌設置的時間,一般用INFINITE表示無限等待事 件的發生,如果其它線程運行有誤,很容易使這個線程死住(等待一個永不發生的事件)。
其實直接用Windows API函數也可以很方便地實現事件(Event)、信號燈(semaphore)控制技術。尤其是C++Builder,在調用Windows API方面有著其它語言無可比擬的優勢。所用的函數主要有:CreateSemaphore()、CreateEvent()、WaitForSingleObject()、ReleaseSemaphore()、SetEvent()等等,這裡就不贅述了。
本文結合Inprise(Borland)公司開發的強大的RAD工具C++Builder的編程,對Windows下的多線程編程作了比較全面的介紹。其實多線程的實現並不神秘,看了本文,你也可以編出自己的多線程程序,真正體會多任務操作系統的威力。
如何判斷一個執行緒已經結束
Terminoated可以判斷是否結束運行,如果你的執行緒是自動回收的(加這行FreeOnTerminate=true),那麼結束後將釋放記憶體。否則要用delete。否則可以重新使用,不用new。
在程式中如何知道一個執行緒已經結束。例如用Terminated屬性。不過這個屬性是私有的,只能在Excute()中用,在執行緒外部要判斷就不能用他了。在執行緒外部判斷執行緒是否結束, 如果是這樣的話,只有兩種方法:一是你在子執行緒的類中加一個全域變數,在結束前一句上改變它的值,那就可以了。而我覺得更好的方法是在子執行緒結束前,用SenMessage/PostMessage 來發送一個自訂的消息。
在執行緒外面可以用GetExitCodeThread看執行緒是否已經退出。
如果你的執行緒是用VCL中的TThread類派生出來的,可以在主程中這樣使用
主程序:
TMyThread * thread;
thread = new TMyThread(true);// 創建執行緒並將其設為暫停狀態
thread -> FreeOnTerminate = false ; 執行緒結束後不自動釋放對象
thread -> Resume(); // 執行執行緒
...
thread -> Terminate(); // 退出執行緒
thread -> WaitFor(); // 主程序等待中的執行緒結束,後此函數才返回
delete thread; // 釋放執行緒對象
執行緒中:
void __fastcall TMyThread::Execute()
{
while( !Terminated)
{
...
}
}
主程序:
TMyThread * thread;
thread = new TMyThread(true);// 創建執行緒並將其設為暫停狀態
thread -> FreeOnTerminate = false ; 執行緒結束後不自動釋放對象
thread -> Resume(); // 執行執行緒
...
thread -> Terminate(); // 退出執行緒
thread -> WaitFor(); // 主程序等待中的執行緒結束,後此函數才返回
delete thread; // 釋放執行緒對象
執行緒中:
void __fastcall TMyThread::Execute()
{
while( !Terminated)
{
...
}
}
2012年1月5日 星期四
memtest86 4.0a/4.0b(server) 多核心測試軟體(千呼萬喚始出來)
期待已久的多核心測試軟體Memtest86 Original版已經出版,而且還分(工作站/伺服機Server版本),可見不久的未來,Memtest86+版也會update到這個多核心的功能。記憶體容量越做越大,測試時間也會相對的增加,軟體工程早已支援多核心架構,但記憶體測試軟體由於演算法及定址等特殊因素,不能與當下多核心執行架構完全相同,雖然RST已經有釋出多核測試版本。但memtest卻遲遲未跟上。這也不能怪它,畢竟是Free版。雖然目前版本還沒有像Memtest86+可以compile後,加上Exe的執行檔頭,製作程DOS Env下的執行檔,但我覺得這應該不是難事,總之先Try看看,到底時間可以省多少,嚴謹度是否有差異,都是須要作比對分析的。
以下就來說明如何製作成DOS環境下的Exe執行檔:
1.首先我們須先download memtest86+ 4.20版的source code。解壓縮之後呢,找到ma86+_loader.asm並存放到我們現在所要作的memtest86 4.0a版目錄下。
待敘‧‧‧
--> 閱讀更多...
以下就來說明如何製作成DOS環境下的Exe執行檔:
1.首先我們須先download memtest86+ 4.20版的source code。解壓縮之後呢,找到ma86+_loader.asm並存放到我們現在所要作的memtest86 4.0a版目錄下。
待敘‧‧‧
2011年12月7日 星期三
我的CJSCOPE JS-131HR新NB
為什麼會選擇這個牌子ㄋ?當然是為了荷包和性能。就是C/P值啦。目前使用至今算是非常滿意,重量真的很輕(和ULTRA BOOK比也才多個300g)。加到8G的RAM後同時開了3個虛擬機還真是非常順暢,四核心加上HT技術果然和兩年前買的Core 2 Due有明顯的效能差異。編譯linux核心也不用等完喝一杯咖啡的時間。
目前VM都只安裝Oracle VirtualBox,為什麼用它呢?優點說不盡,缺點呢:None.。好比說你已在xp使用多年的軟體,偏偏安裝到64bit的win7或Vista就問題一堆。燒錄軟體、很多Embeded的軟體也都只有for 2k/Xp。這時候你就等於買了一部實體NB,但卻擁有N部虛擬computer,只要你的RAM夠大,同時開10個OS也不怕。所以我目前已經開始再觀察512*8的DRAM IC價格。當它來到了平民價,且品質也趨於穩定就是將我的寶貝增加到16GB的時候了。說真的,玩GAME也用不到那麼多記憶體;若是您有使用VM才會建議將DRAM擴充到那麼大。
總之,花了21k擁有4核的NB,真的只有這一部。若是您考慮的是這個品牌的存續或日後的維修等問題‧‧‧我想這些都是未知數。所以我願意冒這個險。總之我使用的評價就是"爽"。
為了荷包,我也沒有添購正版Win7,所以只用試用版!!!!!
--> 閱讀更多...
目前VM都只安裝Oracle VirtualBox,為什麼用它呢?優點說不盡,缺點呢:None.。好比說你已在xp使用多年的軟體,偏偏安裝到64bit的win7或Vista就問題一堆。燒錄軟體、很多Embeded的軟體也都只有for 2k/Xp。這時候你就等於買了一部實體NB,但卻擁有N部虛擬computer,只要你的RAM夠大,同時開10個OS也不怕。所以我目前已經開始再觀察512*8的DRAM IC價格。當它來到了平民價,且品質也趨於穩定就是將我的寶貝增加到16GB的時候了。說真的,玩GAME也用不到那麼多記憶體;若是您有使用VM才會建議將DRAM擴充到那麼大。
總之,花了21k擁有4核的NB,真的只有這一部。若是您考慮的是這個品牌的存續或日後的維修等問題‧‧‧我想這些都是未知數。所以我願意冒這個險。總之我使用的評價就是"爽"。
為了荷包,我也沒有添購正版Win7,所以只用試用版!!!!!
2011年11月29日 星期二
x64存儲管理機制初窺
x64存儲管理機制初窺
x64存儲管理機制,經prolj和mik指點,去找intel手冊和AMD手冊看,看完之後把我的理解寫下,
如有什麼理解偏差之處,還望各位不要笑話。
如有什麼理解偏差之處,還望各位不要笑話。
1.長模式(long mode)
在AMD64架構的長模式中包括兩個子模式:64bit模式和compatibility模式。
● 64bit模式:在此模式中虛擬位址空間使用平坦(flat)模式,段寄存器包括CS,DS,ES,SS全部清零(FS,GS除外,在線性位址計算時,提供額外的base寄存器定址某些OS的系統資料結構),能為64bit的OS和應用程式提供64位元定址支援。
●compatiblity模式:在此模式中使用與lagecy保護模式一樣的存儲管理模式,為的是平滑運行32bit和16bit的應用程式,無需重新編譯,注意:在長模式中不支援真實模式和虛擬8086模式!!
在AMD64架構的長模式中包括兩個子模式:64bit模式和compatibility模式。
● 64bit模式:在此模式中虛擬位址空間使用平坦(flat)模式,段寄存器包括CS,DS,ES,SS全部清零(FS,GS除外,在線性位址計算時,提供額外的base寄存器定址某些OS的系統資料結構),能為64bit的OS和應用程式提供64位元定址支援。
●compatiblity模式:在此模式中使用與lagecy保護模式一樣的存儲管理模式,為的是平滑運行32bit和16bit的應用程式,無需重新編譯,注意:在長模式中不支援真實模式和虛擬8086模式!!
由於在64bit模式下使用flat模式,所以無lagecy保護模式下的分段管理模式,所以虛擬位址直接對應線性位址。所以x64的分頁管理模式才是64bit下的重頭戲
2.x64分頁管理模式
如下圖,是x86-64下的所有頁大小和物理位址大小的匯總.
2.x64分頁管理模式
如下圖,是x86-64下的所有頁大小和物理位址大小的匯總.
在x64下,理論上可以通過使用PAE(實體位址擴充)分頁結構支援64bit的線性位址到52bit物理位址的映射的,但在對這一架構的首次實現中,只實現了48位元的線性位址到40位元物理位址的映射。現在你可以通過CPUID指令查看自己的cpu所支援的最大物理位址(MAXPHYDDR).
大家一定還記得在lagecy保護模式下通過PAE功能來訪問超過32bit(36bit)的物理位址,但是在x64模式下的PAE與先前的PAE是不一樣的!!
從線性位址到物理位址的轉換中用到了四級頁資料結構,一個新的頁表資料結構---PML4被引入用來指向頁目錄指標表。PML4表只能在x64模式下使用。而且頁目錄表指標從原來的4個項增加到了512個,所以要從線性位址中分配9bit用來索引PDP表(原來是2bit)。
PDE和PTE的大小保持不變。所以我們可以看到PML4+PDP+PDE+PTE+page offset=48bit,高16bit保留(其實是用以符號擴展,下面將看到符號擴展的用途)。
CR3指向了PML4的基底位址。
需要注意的是在使用x64模式之前,必須使CR4.PAE=1(PAE用來擴展PDE和PTE至64bit)。如果你在未使CR4.PAE=1之前,企圖開啟x64模式的話,會引發#GP異常。
我們從上圖還可以看到頁大小的選擇完全取決於PDE.PS(但我並沒有在文檔中看到ps位,是直接在文檔中置1或0),無視CR4.PSE的存在。
2.1x64分頁管理(4kb)
上圖再說
大家一定還記得在lagecy保護模式下通過PAE功能來訪問超過32bit(36bit)的物理位址,但是在x64模式下的PAE與先前的PAE是不一樣的!!
從線性位址到物理位址的轉換中用到了四級頁資料結構,一個新的頁表資料結構---PML4被引入用來指向頁目錄指標表。PML4表只能在x64模式下使用。而且頁目錄表指標從原來的4個項增加到了512個,所以要從線性位址中分配9bit用來索引PDP表(原來是2bit)。
PDE和PTE的大小保持不變。所以我們可以看到PML4+PDP+PDE+PTE+page offset=48bit,高16bit保留(其實是用以符號擴展,下面將看到符號擴展的用途)。
CR3指向了PML4的基底位址。
需要注意的是在使用x64模式之前,必須使CR4.PAE=1(PAE用來擴展PDE和PTE至64bit)。如果你在未使CR4.PAE=1之前,企圖開啟x64模式的話,會引發#GP異常。
我們從上圖還可以看到頁大小的選擇完全取決於PDE.PS(但我並沒有在文檔中看到ps位,是直接在文檔中置1或0),無視CR4.PSE的存在。
2.1x64分頁管理(4kb)
上圖再說
●sign extended--符號擴展位元
●PML4 entry--在線性位址39~47bit用於索引PML4 entry,指向PDP
●PDP entry--在線性位址的30~38bit用來索引PDP entry,指向PDE
●PDE entry--在線性位址的21~29bit用來索引PDEentry,指向PTE
●PTE entry--在線性位址的12~20bit用來索引PTE entry,指向page offset
●page offset--在線性位址的0~11bit提供在頁中的offset
2.2x64分頁管理(2mb)
●PDP entry--在線性位址的30~38bit用來索引PDP entry,指向PDE
●PDE entry--在線性位址的21~29bit用來索引PDEentry,指向PTE
●PTE entry--在線性位址的12~20bit用來索引PTE entry,指向page offset
●page offset--在線性位址的0~11bit提供在頁中的offset
2.2x64分頁管理(2mb)
我們可以看到與4kb的頁相比少了PTE,page offset從原來的12bit增加到了21bit下面我們來看看各分頁表項目的內部結構.
(4kB)上圖看到,用上述方法可以得到512×512×512×512=2^36個頁面,2^36*4kb=2^48個線性位址.
上圖看到,用上述方法可以得到512×512×512=2^27個頁面,2^27*2mb=2^48個線性位址 0bit:P位,即存在位,表示由項所指的頁面或頁表當前是否載入到了物理記憶體中,如不存在,可以通過引發#PF異常從磁片中載入到物理記憶體中
1bit:R/W,即讀寫位,為頁表指定讀寫特權,當置位時可讀可寫;清零是唯讀
2bit:使用者/系統位元,即為頁表指定系統還是普通使用者特權
3bit:頁面通寫,指定快取記憶體寫策略是回寫還是通寫
4bit:快取記憶體禁止位,當置位元時禁止相關的頁面和頁表進行快取記憶體,反之,可以
5bit:訪問位,當置位時表示已經被訪問,反之,沒有
6bit(非PTE或PDE(2MB)):可用位
6bit(PTE或PDE(2MB)):D位,dirty,即髒位,置位元時表示頁面被寫過
7~8bit(非PTE或PDE(2MB)):0
avail:系統程式師可用
G:全域標誌
PAT:頁表屬性
各種base address是用來得到下一級表的基底位址的,最後的物理位址=page base address*2^12(2^21)+2^12(2^21),而page base address的大小取決於你的cpu的最大物理位址了。
3.最後,我來看一看sign extended會形成什麼效果。
由於sign extended的作用會將線性位址分成相同大小的兩段,從0至00007FFF`FFFFFFFF,以及從 FFFF8000`00000000至FFFFFFFF`FFFFFFFF總計256TB的地址範圍,這非常符合作業系統的習慣。
這種“古怪”的規則為日後擴展到真正的64位定址保留了一個重要的特性:很多的作業系統(包括但不限於Windows NT系列)將位址空間的高半部分(被稱作內核空間)留給自己,將低半部分(使用者空間)留給應用程式碼、用戶態棧、堆和其他數據區。這種設計保證了每一個符合AMD64的實現都擁有兩個記憶體片段:低半段從00000000`00000000開始,隨著更多的虛擬位址位元變得可用而“向上生長”;高半部分被“懸掛”在位址空間的頂部而“向下生長”。同樣,將未被使用的位址位元內容固定下來防止被作業系統用作標誌位元、特權級標號等其他用途,是為了避免當架構擴展至52,56, 60 和64位的時候出現問題。
2bit:使用者/系統位元,即為頁表指定系統還是普通使用者特權
3bit:頁面通寫,指定快取記憶體寫策略是回寫還是通寫
4bit:快取記憶體禁止位,當置位元時禁止相關的頁面和頁表進行快取記憶體,反之,可以
5bit:訪問位,當置位時表示已經被訪問,反之,沒有
6bit(非PTE或PDE(2MB)):可用位
6bit(PTE或PDE(2MB)):D位,dirty,即髒位,置位元時表示頁面被寫過
7~8bit(非PTE或PDE(2MB)):0
avail:系統程式師可用
G:全域標誌
PAT:頁表屬性
各種base address是用來得到下一級表的基底位址的,最後的物理位址=page base address*2^12(2^21)+2^12(2^21),而page base address的大小取決於你的cpu的最大物理位址了。
3.最後,我來看一看sign extended會形成什麼效果。
由於sign extended的作用會將線性位址分成相同大小的兩段,從0至00007FFF`FFFFFFFF,以及從 FFFF8000`00000000至FFFFFFFF`FFFFFFFF總計256TB的地址範圍,這非常符合作業系統的習慣。
這種“古怪”的規則為日後擴展到真正的64位定址保留了一個重要的特性:很多的作業系統(包括但不限於Windows NT系列)將位址空間的高半部分(被稱作內核空間)留給自己,將低半部分(使用者空間)留給應用程式碼、用戶態棧、堆和其他數據區。這種設計保證了每一個符合AMD64的實現都擁有兩個記憶體片段:低半段從00000000`00000000開始,隨著更多的虛擬位址位元變得可用而“向上生長”;高半部分被“懸掛”在位址空間的頂部而“向下生長”。同樣,將未被使用的位址位元內容固定下來防止被作業系統用作標誌位元、特權級標號等其他用途,是為了避免當架構擴展至52,56, 60 和64位的時候出現問題。
參考資料:
2011年10月6日 星期四
如何使用Bochs來Debug GRUB2 & Kernel
参考以下文章:
http://www.linuxsir.org/bbs/thread356982.html
http://man.he.net/man8/grub-setup
http://blog.csdn.net/zhouyelihua/article/details/6683437
http://www.gnu.org/software/grub/manual/grub.html#Installing-GRUB-using-grub_002dinstall
http://read.pudn.com/downloads153/ebook/675818/linux-0.11-040304/bochsrc-hd-new.bxrc__.htm
只創建一個主要磁碟分割就可以,並設定 [使可開機] , 寫入後, 用命令fdisk檢查結果。
bochs -f bochsrc.bxrc 雖然會顯示unknown filesystem
解決辦法:
grub rescue>set prefix=(hd0,1)/boot/grub
grub rescue>root=(hd0,1)
grub rescue>insmod normal
grub rescue>normal
這樣就可以回到grub> 或選單狀態了。
此時也可以輸入help及其他command line指令了。
接著我們來試試如何使用gdb來debug GRUB2:
先在bochsrc.bxrc最後面加入幾行來使gdb connect to Bochs:
現在先開啟另一個終端輸入gdb,並重新啟動bochs -qf bochsrc.bxrc指令
gdb會出現如下畫面:藍色字為輸入指令
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
(gdb) target remote localhost:1234
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from /home/benson/kernel.exec...done.
(gdb) b
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000e05c in ?? ()
(gdb) c
Continuing.
Breakpoint 1, grub_main () at kern/main.c:175
warning: Source file is more recent than executable.
175
(gdb) list
170 void
171 grub_main (void)
172 {
173 /* First of all, initialize the machine. */
174 grub_machine_init ();
175
176 /* Hello. */
177 grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
178 grub_printf ("Welcome to GRUB!Benson Debug Here!\n\n");
179 grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
(gdb)
執行過程如下圖所示:
這張圖是修改過source code,所以下一張圖會多出Benson Debug Here!字樣。
若是你的gdb無法connect到bochs,可能你須要重新build一次Bochs,動作如下:
註:--enable-gdb-stub和--enable-debugger是互斥的
1 ./configure --enable-gdb-stub
2 make
3 sudo make install
update.....
--> 閱讀更多...
http://www.linuxsir.org/bbs/thread356982.html
http://man.he.net/man8/grub-setup
http://blog.csdn.net/zhouyelihua/article/details/6683437
http://www.gnu.org/software/grub/manual/grub.html#Installing-GRUB-using-grub_002dinstall
http://read.pudn.com/downloads153/ebook/675818/linux-0.11-040304/bochsrc-hd-new.bxrc__.htm
由於bochs內建調試功能, 且支援gdb, 用它調試內核會很方便.
假設你已經build好grub,這裡我舉的例子是使用grub1.99,若還沒有Build,現在正是時候:
1 ./configure CFLAGS=-g
2 make
3 sudo make install
在ubuntu下預設是安裝到usr/local/lib/grub/i386-pc,別擔心會影響到您的開機MBR,因為make install只是將一些GRUB的各個executable Binary及mod模組存放到指定的prefix,除非你執行grub-install和update-grub 等指令才有可能去動到MBR。
以下指令請使用Root身份執行
1 ./configure CFLAGS=-g
2 make
3 sudo make install
在ubuntu下預設是安裝到usr/local/lib/grub/i386-pc,別擔心會影響到您的開機MBR,因為make install只是將一些GRUB的各個executable Binary及mod模組存放到指定的prefix,除非你執行grub-install和update-grub 等指令才有可能去動到MBR。
以下指令請使用Root身份執行
1.1構建磁碟影像檔:dd if=/dev/zero of=hd0.img count=$((63*16*100))
用這個命令可以構建一個50MB左右的磁片鏡像, 輸出結果如下:
100800+0 records in
100800+0 records out
51609600 bytes (52 MB) copied, 0.734578 s, 70.3 MB/s
注意count必須為63*16的倍數, 否則bochs識別硬碟會有問題.
1.2 掛載磁碟影像:losetup /dev/loop0 hd0.img
這個命令可以將檔綁定到一個loop設備. 如果/dev/loop0不存在, 可以嘗試 modprobe loop.
然後進行設備初始化:cfdisk -s 63 -h 16 /dev/loop0
畫面如下橘色文字:
cfdisk (util-linux-ng 2.17.2)
硬碟: /dev/loop0
大小: 51609600 位元組(B), 51 MB
磁頭: 16 每一磁軌的磁區數: 63 磁柱數: 100
分割區名稱 屬性旗標 分割區型態 檔案系統型態 標記名稱 大小 (MB)
------------------------------------------------------------------------------
主要/邏輯 剩餘空間 51.61
[ 說明 ] [ 新增 ] [ 列印 ] [ 離開 ] [ 單位 ]
[ 寫入 ]
由剩餘空間切一個新的分割區
指令:fdisk -lu /dev/loop0 結果畫面如下:當然Linux版本不同,畫面難免大同小異
磁碟 /dev/loop0: 51 MB,51609600 位元組
16 磁頭,63 磁區/磁軌,100 磁柱,總計 100800 磁區
單位 = 磁區 之於 1 * 512 = 512 位元組
磁區大小 (邏輯/實體):512 位元組 / 512 位元組
I/O 大小 (最小/最佳化):512 位元組 / 512 位元組
磁碟識別碼:0x00000000
所用裝置 開機 開始 結束 區塊 識別號 系統
/dev/loop0p1 * 63 100799 50368+ 83 Linux
接著將分區1掛載到/dev/loop1:losetup /dev/loop1 hd0.img -o $((63*512))
格式化/dev/loop1為ext3格式.:mkfs.ext3 /dev/loop1
在mnt下創建img目錄, 做以後維護用:mkdir -p /mnt/img
將loop1掛載到/mnt/img:mount /dev/loop1 /mnt/img/
安裝引導程式. 因為我狂熱傾向於模組化架構, 所以選擇GRUB2.
mkdir /mnt/img/bootcp -r /usr/lib/grub/i386-pc/ /mnt/img/boot/grub
這個/usr/lib/grub/i386-pc是你的GRUB2安裝路徑,像我的1.98及1.99版在ubuntu下是安裝在以下路徑:/usr/local/lib/grub/i386-pc接著生成一個core.img, biosdisk模組負責讀取磁片, part_msdos模組負責處理MBR,ext2模組負責讀取ext3分區:
cd /mnt/img/boot/grub/
grub-mkimage -o core.img biosdisk part_msdos ext2 #1.98版使用這個指令
grub-mkimage -O i386-pc -o core.img biosdisk part_msdos ext2 #1.99版使用這個指令
grub-mkimage -O i386-pc -o core.img biosdisk part_msdos ext2 #1.99版使用這個指令
注意,這個core.img還不是個可開機用的影像檔。它並未包含boot.img及diskboot.img。
接著安裝grub2到(hd0), 根目錄在(hd0,1)
echo "(hd0) /dev/loop0" > ./device.map
grub-setup -m ./device.map -d /mnt/img/boot/grub/ -r '(hd0,1)' '(hd0)'
其實上面這2行也可以用下面一行取代
grub-setup -d /mnt/img/boot/grub/ --force /dev/loop0
檢查一下/dev/loop0安裝成果:
hexdump -C /dev/loop0 | less
00000180 7d e8 2e 00 cd 18 eb fe 47 52 55 42 20 00 47 65 |}.......GRUB .Ge|
00000190 6f 6d 00 48 61 72 64 20 44 69 73 6b 00 52 65 61 |om.Hard Disk.Rea|
清理一下離開終端,重新開一個終端,否則umount會失敗,若你不是以root執行的話
umount /mnt/img
losetup -d /dev/loop1
losetup -d /dev/loop0
2.1建立.bochsrc檔如下:說明一下,在linux下預設是讀取.bochsrc這個檔名,所以你若創建一個叫bochs.bxrc或其他檔名,則等一下開啟bochs時,指令如下:
bochs -q -f bochs.bxrc,否則只須下bochs -q
bochs -q -f bochs.bxrc,否則只須下bochs -q
###############################################################
# bochsrc.bxrc file for kenos disk image.
###############################################################
megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-legacy, address=0xf0000
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
# hard disk
ata0-master: type=disk, mode=flat, path="/home/benson/working_benson/DBG_grub/hd0.img", cylinders=100, heads=16, spt=63
#ata0-slave: type=cdrom, path="/home/marc/setups/slax-6.0.9.iso", status=inserted
# choose the boot disk.
boot: c
# where do we send log messages?
log: bochsout.txt
# disable the mouse, since DLX is text only
mouse: enabled=0
keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-us.map
#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-fr.map
#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-de.map
#keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-es.map
#cpu: count=1, ips=10000000
# Make the PIT emulated by bochs tick at the correct interval. Note that
# enabling this feature sacrifices reproducibility, which may be a problem
# at times when tracking a specific bug.
#clock: sync=realtime, time0=utc
# For debugging with gdb.
# Keep this line when using bochs-gdb.
# Comment it out when using bochs-dbg
# See http://bochs.sourceforge.net/doc/docbook/user/bochsrc.html#BOCHSOPT-GDBSTUB
#gdbstub: enabled=1, port=1234, text_base=0, data_base=0, bss_base=0
使用bochs開啟hd0.imgbochs -f bochsrc.bxrc 雖然會顯示unknown filesystem
解決辦法:
grub rescue>set prefix=(hd0,1)/boot/grub
grub rescue>root=(hd0,1)
grub rescue>insmod normal
grub rescue>normal
這樣就可以回到grub> 或選單狀態了。
此時也可以輸入help及其他command line指令了。
接著我們來試試如何使用gdb來debug GRUB2:
先在bochsrc.bxrc最後面加入幾行來使gdb connect to Bochs:
# Attach ne2000 to PCI bus, so that GRUB Legacy detects it automatically
i440fxsupport: enabled=1, slot1=ne2k
# Enable the ne2000 NIC and the builtin TFTP server
ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="/"
# Enable the GDB remote stub
gdbstub: enabled=1
現在先開啟另一個終端輸入gdb,並重新啟動bochs -qf bochsrc.bxrc指令
gdb會出現如下畫面:藍色字為輸入指令
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x0000fff0 in ?? ()
(gdb)file kernel.exec
Are you sure you want to change the file? (y or n) y
Reading symbols from /home/benson/kernel.exec...done.
(gdb) b
No default breakpoint address now.
(gdb) b mainBreakpoint 1 at 0xc4fd: file kern/main.c, line 175.
(gdb) cContinuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x0000e05c in ?? ()
(gdb) c
Continuing.
Breakpoint 1, grub_main () at kern/main.c:175
warning: Source file is more recent than executable.
175
(gdb) list
170 void
171 grub_main (void)
172 {
173 /* First of all, initialize the machine. */
174 grub_machine_init ();
175
176 /* Hello. */
177 grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
178 grub_printf ("Welcome to GRUB!Benson Debug Here!\n\n");
179 grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
(gdb)
執行過程如下圖所示:
這張圖是修改過source code,所以下一張圖會多出Benson Debug Here!字樣。
若是你的gdb無法connect到bochs,可能你須要重新build一次Bochs,動作如下:
註:--enable-gdb-stub和--enable-debugger是互斥的
1 ./configure --enable-gdb-stub
2 make
3 sudo make install
update.....
訂閱:
文章 (Atom)













