程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 簡易軟盤鏡像工具的實現及操作系統編寫初步

簡易軟盤鏡像工具的實現及操作系統編寫初步

編輯:關於VC++

摘要

本文給出了軟盤鏡像生成工具的實現,並用其把自己編譯生成的引導 文件制作成軟盤鏡像,寫入軟盤實現一個簡單操作系統的引導。

關鍵詞 軟盤鏡像工具 操作系統引導。

為了深入的了解80X86計算機的內部原理 ,參照別人的程序用匯編寫了幾個小程序。但生成軟盤鏡像的工具大都是DOS版 本的,於是就想自己用VC也實現一個,並用把自己的引導程序寫入軟盤上驗證一 下。

1、鏡像工具的基本原理

鏡像工具讀取磁盤上的文件,然後 安裝一定的格式生成軟盤鏡像文件,最後把軟盤鏡像文以512字節扇區為單位, 寫入軟盤上。

2、鏡像工具的界面設計及功能介紹

圖1 主界面

2.1 【功能1】生成軟盤鏡像文件

(1)要生成鏡像文件, 需要先選擇源文件,然後點擊【生成…】,如MyDiskImg.img,點擊【保存 】生成鏡像文件。

圖2 生成鏡像文件

(2)然後插入一張軟盤,點擊寫軟盤,選擇剛生成的鏡像 文件。點擊【打開】,系統便開始把選擇的鏡像文件寫入軟盤中。

圖3 把鏡像文件寫入軟盤

(3)重新啟動計算機,選擇從軟盤啟動,看操作是 否成功。

3、具體代碼編寫

3.1 生成軟盤鏡像代碼

基本原 理為對列表中的源文件依次讀取,然後寫入到一個img文件中,具體的代碼請參考( 省略了部分不關鍵代碼):

//生成鏡像文件函數
UINT FuncGenImageFile(LPVOID pDialog)
{
  //Begin 顯示設置
  省略…
  //1.創建輸出鏡像文件
  byte* pBuf = NULL;
  DWORD count = 0,dwFileLength=0;
  CFile outfile;//鏡像文件
  if(!outfile.Open(pCurDlg- >m_ImgFileName,CFile::modeCreate | CFile::modeWrite))
  {
    錯誤提示…
      return -1;
  }

  //2.依次對輸入文件讀取,寫入輸出鏡像文件
  for( int i = 0 ; i < pList->GetCount(); ++i )
  {
     CString sInFileName;
    pList->GetText(i,sInFileName);
    CFile infile;

    if(!infile.Open (sInFileName,CFile::modeRead))
    {
      錯誤提 示…
        return -1;
    }
     dwFileLength = infile.GetLength();
    if(i==0)
     {
      if(dwFileLength>512)
      {
        sOut.Format(_T("文件%S不是一個有效的引導區文件,請 使用[功能3]裁減該文件!"),sInFileName);
         return -1;
      }
    }
    if(i==0)//對 0扇區文件進行特殊處理
    {
      pBuf = new byte [BlOCKSIZE];
      ::memset(pBuf,0,BlOCKSIZE);
       infile.Read(pBuf,dwFileLength);
      if(pBuf[510]! =0x55) pBuf[510]=0x55;
      if(pBuf[511]!=0xAA) pBuf[510] =0xAA;
      outfile.Write(pBuf,BlOCKSIZE);
       dwFileLength = BlOCKSIZE;
    }
    else
     {
      pBuf = new byte[dwFileLength];
       infile.Read(pBuf,dwFileLength);
      outfile.Write (pBuf,dwFileLength);
    }
    infile.Close() ;

    delete[] pBuf;
    count += dwFileLength;
    pProgCtrl->SetPos((int)(count*100/FLOPYBYTESIZE));
    }

#ifdef ADISKMODE
  //3.補充剩余的軟盤字節 為0
  DWORD dwRet = FLOPYBYTESIZE-count;
  pBuf = new byte[dwRet];
  memset(pBuf,0,dwRet);
  outfile.Write (pBuf,dwRet);
  delete[] pBuf;
#endif
   outfile.Close() ;

  //end 顯示設置
  省略 …
    return 0;
}

3.2 寫鏡像文件到軟盤代碼

基本原理是讀取生成的鏡像文件,然後把其寫入軟盤啟動器A中, 具體的 代碼請參考(省略了部分不關鍵代碼):

//寫鏡像文件到軟驅

UINT FuncWriteFlopy(LPVOID pDialog)
{
  //begin 顯示設置
  省略…
    int nTotalBlocks = 80*18*2;

  //1.打開A驅動器
  HANDLE  hFile = CreateFile(_T("\\\\.\\A:"),
    GENERIC_WRITE,
     FILE_SHARE_WRITE,
    NULL,
     OPEN_EXISTING,
    0,
    NULL);
  if (hFile==NULL)
  {
    sOut = _T("不能打開驅動器 A");//…
    return -1;
  }

   PBYTE pBuffer = (PBYTE)malloc(BlOCKSIZE);
  if(pBuffer==NULL)
  {
    sOut = _T("開辟內存空間失敗! ");//…
    return -1;
  }
  memset (pBuffer,0,BlOCKSIZE);
  //2.打開鏡像文件
  CFile fInFile;
  BOOL b = fInFile.Open(pCurDlg->m_ImgFileName, CFile::modeRead);
  if(!b)
  {
    sOut.Format (_T("不能打開鏡像文件%s!"),pCurDlg->m_ImgFileName);
    …
      return -1;
  }

   //3.分塊寫入鏡像文件
  DWORD dwImgLen = fInFile.GetLength ();
  for(int i=0;i<nTotalBlocks;i++)
  {
     DWORD dwLen=0;
    fInFile.Read(pBuffer, BlOCKSIZE);
    WriteFile(hFile, pBuffer, BlOCKSIZE, &dwLen, NULL);

#ifndef ADISKMODE
    if((DWORD)((i+1)*BlOCKSIZE) >=dwImgLen) break;//鏡像文件寫入完畢
#endif
    if (dwLen!=BlOCKSIZE)
    {
      sOut.Format(_T ("寫入鏡像文件%s失敗,請檢查軟驅!"),pCurDlg- >m_ImgFileName);
      //…
       return -1;

    }
    pProgCtrl->SetPos ((int)(i*100/nTotalBlocks));
  }

  //4.關閉文件
  fInFile.Close();
  CloseHandle(hFile);
  free (pBuffer);

  //end 顯示設置
  pProgCtrl- >SetPos(100);
  sOut.Format(_T("鏡像文件%s寫入軟驅成 功!"),pCurDlg->m_ImgFileName);
  //…
   return 0;
}

4、操作系統編寫

4.1 PC機啟動基本原理

(1) 開啟電源後, 機器就會開始執行ROM BIOS的一系列系統測試動作, 包括檢查RAM,keyboard,顯示器,軟硬磁盤等等。

(2)執行完BIOS的系 統測試之後,緊接著控制權會轉移給ROM中的啟動程序(ROM bootstrap routine) ;這個程序會將磁盤上的第0軌第0扇區(叫boot sector或MBR ,系統的引導程 序就放在此處)讀入內存中,並放到自0x07C0:0x0000開始的512個字節處;然後 處理機將跳到此處開始執行這一引導程序;也即裝入MBR中的引導程序後, CS:IP = 0x07C0:0x0000 。

注意: 如果這個扇區的最後兩個字節是 "55 AA",那麼這就是一個引導扇區。如果最後兩個字節不是 "55 AA",那麼BIOS 就檢查下一個磁盤驅動器。

4.2 基本編 譯工具選擇

NASM:編寫系統級匯編代碼的絕好的工具,而且分別支持 Windows和Linux系統。本來原來用TASM編譯的,可發現在編寫的讀取硬盤扇區的 匯編代碼裁剪去512字節的DOS頭後居然不能還運行,郁悶了好多天,都沒有解決 ,而用NASM編譯出來可以的,所以決定改用NASM。

4.3 引導代碼編寫

文件boot.asm,具體代碼及注釋

org 07c00h  ; 程序會被加載到 7c00處,所以需要這一句
mov ax, cs
mov ds, ax
mov es, ax
Call DispStr  ; 調用顯示字符串例程
jmp $  ; 無限循環
DispStr:
mov ax, BootMessage
mov bp, ax  ; ES:BP = 串地址
mov cx, 16  ; CX = 串長度
mov ax, 01301h ; AH = 13h, AL = 01h
mov bx, 000ch ; 頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮)
mov dl, 0
int 10h  ; int 10h
ret
BootMessage:  db   " Hello, OS world!"
times 510-($-$$) db  0 ;填充剩下 的空間,使生成的二進制代碼恰好為512字節
dw 0aa55h  ; 引導扇區需 要以55AA結束

4.4 用NASM編譯

nasm boot.asm -o boot.bin

4.5 寫入鏡像文件及運行

按照2.1節所示的步驟把 boot.Bin生成鏡像文件,然後再寫入軟盤。下圖是我再VMWare下的運行結果:

圖4 系統運行顯示

4.6 系統的其它功能實現

讀取硬盤扇區 ,BIOS中斷向量替換,實現文件系統,實虛模式轉換及磁盤文件加載由於自己水 平有限,不能詳細介紹,網上有許多高手已經實現得很好了。如果感興趣,可以參 考相應的網址。詳細請見:http://www.oldlinux.org

結語

本文 中的部分代碼來自網上及林永君老師的課件,在此表示感謝。當然,單純做一個 操作系統來說,其現實的意義已不是太大。但對於更好的了解PC機的運行機制及 操作系統的中斷向量,系統調動及實模式及虛模式還是有很大的意義的。另外, 也可以為Linux或者Windows下的驅動及系統開發打下一個良好的基礎。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved