codefans

          導航

          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          統計

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          程序設計鏈接

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          [開發教程][原創] 操作系統DIY - 啟動你的計算機

          預備知識:
            匯編語言、能讀懂NASM語法、了解BIOS 中斷INT0x10, INT 0x16,虛擬機的使用

          涉及工具:
            NASM,一個文本編輯器(我用的是ConText + NASM語法高亮)

          前言:
            第一次寫教程,不知道能拿多少分。

            “怎樣開始寫自己的操作系統”可能是不少有“非分想法”的愛好者來說是一個難題,在我的大學課程《計算機操作系統教程》以教程的形式充分說明了操作系統的原理,這本書會告訴你各個環節的原語;所謂“原理”就指理論上的東西,實際上我們并不知道操作系統是如何工作的。為了不至于讓有這個非分想法的朋友不至于放棄,這篇日志就帶你走進操作系統開發的殿堂。

          一、操作系統是如何啟動的?

            首先讓我們來看看計算機的啟動過程,這里我摘抄了一些東西:

            “首先讓我們來了解一些基本概念。第一個是大家非常熟悉的BIOS(基本輸入輸出系統),BIOS是直接與硬件打交道的底層代碼,它為操作系統提供了控制硬件設備的基本功能。BIOS包括有系統BIOS(即常說的主板BIOS)、顯卡BIOS和其它設備(例如IDE控制器、SCSI卡或網卡等)的BIOS,其中系統BIOS是本文要討論的主角,因為計算機的啟動過程正是在它的控制下進行的。BIOS一般被存放在ROM(只讀存儲芯片)之中,即使在關機或掉電以后,這些代碼也不會消失。

            “第二個基本概念是內存的地址,我們的機器中一般安裝有32MB、64MB或128MB內存,這些內存的每一個字節都被賦予了一個地址,以便CPU訪問內存。32MB的地址范圍用十六進制數表示就是0~1FFFFFFH,其中0~FFFFFH的低端1MB內存非常特殊,因為最初的8086處理器能夠訪問的內存最大只有1MB,這1MB的低端640KB被稱為基本內存,而A0000H~BFFFFH要保留給顯示卡的顯存使用,C0000H~FFFFFH則被保留給BIOS使用,其中系統BIOS一般占用了最后的64KB或更多一點的空間,顯卡BIOS一般在C0000H~C7FFFH處,IDE控制器的BIOS在C8000H~CBFFFH處。”

            (以上引自:http://article.pchome.net/2003/09/25/13022.htm

          二、進一步了解引導的關鍵所在

            計算機啟動的第一個過程由BIOS完成,它做了什么工作是不我們不必理會的,我們也管不了那它;關鍵在于:BIOS完成設備檢查、初始化、更新之后,根據預先設定的引導設備順序檢查可以引導的設備,比如我們設置啟動順序為1:Floppy(軟驅)2:HDD1(硬盤1) 3:CD-ROM(光驅),那么,BIOS會從軟驅開始查找是否可以啟動,如果軟驅失敗,則會去找HDD1,......
            那么,BIOS如何知道軟盤或硬盤能不能引導呢?這個把戲的關鍵在于:每個可引導設備都有一個512字節的設備頭,如果這個設備可引導,最后兩個字節必須為0x55(低),0xAA(高),如果BIOS找到這個標志,就會將這512字節(注意:只有512字節)讀到內存的0x0000:0x7C00,然后將控制權轉交給(跳到)0x0000:0x7C00的程序,這就意味著:如果我們將軟盤的第一個扇區最后兩個字節打上"0x55,0xAA"的標志,這個軟盤就可以啟動了!當然,BIOS不會知道你這個引導程序是不是有效的,它只認0x55,0xAA。

            好了,我們知道寫自己第一個引導程序的關鍵在于: 
            1. 一個兩字節(一個字長)的引導標志 0x55,0xAA
            2. 引導程序必須占512字節

          三、看看實例

            代碼用NASM編譯:nasmw -f bin boot.asm -o boot.bin
            解釋一下上面的命令:在M$命令提示行下編譯,-f bin 表示編譯為純二進制文件(我們不需要任何文件頭),-o boot.bin 編譯。

          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          ; boot.asm
          ; A demo to show how bootsect works
          ; Last modified:2005-4-3 10:57:45
          ; Copyright (c) 2005,E-mean X.
          ;
          ; This program is released under GPL,See document for details
          ; You can use this code anywhere you want in condition keep autor's info
          ; original
          ;
          ; Author: E-mean X.
          ; Contact: xemean@sina.com
          ; Website: http://www.xemean.net/
          ; April,02,2005
          ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
          bits 16         ; 偽指令,告訴編譯器這是 16位代碼
          org 0x7C00      ; 偽指令,告訴編譯器這段代碼由0x0:0x7C00開始
          ;===========================================================================
          ; 程序執行的第一條指令必須是跳轉(如果你想使用FAT12這類文件系統的磁盤)
          ; 必須占用3字節
          ;===========================================================================
          jmp SHORT main ; 2 bits,跳轉到主程序執行
          nop            ; 1 bit
          ;===========================================================================
          ; FAT12 文件系統頭,從NYAOS 借過來的,可以參考相關的文檔以獲得更多細節
          ; 這個塊會讓 Winimage 認出編譯后的二進制文件為有效的引導文件
          ; 如果不使用這個塊,Winimage將不會將其作為引導程序處理
          ; 但我們可以借助其它方法和工具處理,比如DEBUG
          ;===========================================================================
          bsOEM       db "ExOS0.01"               ; OEM String,任意你喜歡的8字節ASCII碼
          bsSectSize  dw 512                      ; Bytes per sector
          bsClustSize db 1                        ; Sectors per cluster
          bsRessect   dw 1                        ; # of reserved sectors
          bsFatCnt    db 2                        ; # of fat copies
          bsRootSize  dw 224                      ; size of root directory
          bsTotalSect dw 2880                     ; total # of sectors if < 32 meg
          bsMedia     db 0xF0                     ; Media Descriptor
          bsFatSize   dw 9                        ; Size of each FAT
          bsTrackSect dw 18                       ; Sectors per track
          bsHeadCnt   dw 2                        ; number of read-write heads
          bsHidenSect dd 0                        ; number of hidden sectors
          bsHugeSect  dd 0                        ; if bsTotalSect is 0 this value is
                                                  ; the number of sectors
          bsBootDrv   db 0                        ; holds drive that the bs came from
          bsReserv    db 0                        ; not used for anything
          bsBootSign  db 29h                      ; boot signature 29h
          bsVolID     dd 0                        ; Disk volume ID also used for temp
                                                  ; sector # / # sectors to load
          bsVoLabel   db "NO NAME    "            ; Volume Label
          bsFSType    db "FAT12   "               ; File System type <- FAT 12文件系統
          ;===========================================================================
          ; Main start here
          ;===========================================================================
          main:
               cli  ; 關閉可屏蔽中斷,以備我們接下來初始化寄存器的工作
               mov  ax,cs ; 將代碼段傳給ax,實模式下,代碼段與數據段沒什么分別
               mov  ds,ax ; 數據段寄存器,實際上都是0
               mov  es,ax ; 附加段
               mov  ax,ss ; 堆棧段
               mov  sp,0x7C00-1   ; 堆棧指針,指向0x7BFF
               sti  ; 基本工作已經完成,開放中斷

               ;
               mov  si,msgHello ; 使 si指向 "Hello World!"字符串
               call printStr    ; 調用顯示子程序
              
               mov  si,fixLine  ; 回車換行
               call printStr
              
               mov  si,msgMore  ; 顯示更多信息
               call printStr

               ; Mission complete,take a break
               .loop:
               xor  ax,ax       ; ax 清0
               int  0x16        ; 調用int 16h 讀取鍵盤輸入

          ; 重啟計算機
          ;     mov  ax,0x40
          ;     mov  ds,ax
          ;     xor  ax,ax
          ;     mov  [0x0072],ax  ; 向 0x40:0x72寫0后再跳到_
          ;     jmp  0xFFFF:0x0    ; 0xFFFF:0x0 可以實現重啟

               jmp  .loop       ; 跳轉到 .loop,什么也不做了

          ;------- END OF MAIN ----------------

          ;===========================================================================
          ; printStr
          ; sub function for print a string to screen by INT 10H
          ; 入口:ds:si = 指向目標字符串
          ; 返回:無
          ;===========================================================================
          printStr:
               push si  ; 保護寄存器
               push ax
               push bx

                    cld    ; 清除進位標志位,這個標志位會影響 si 的遞增方向
                    mov  ah,0x0E    ; int 0x10 子功能號,顯示字符,參看相關資料以獲得細節
                    mov  bx,0x0007  ; 頁號0,字符前景色 7,淺灰色,試著改變這個數值
                                    ; 會給你的文字增添色彩
               .nextChar:
                    lodsb           ; [si] -> al,取一個字節碼
                    or  al,al       ; 如果取得的字節是0,則表示字符串結束
                    jz  .OK         ; 退出
                    int 0x10        ; 調用BIOS int 10h 中斷
                    jmp .nextChar   ; 繼續下一個字符,直到遇到0
               .OK:
               pop  bx ; 恢復寄存器
               pop  ax
               pop  si
               ret     ; 返回調用程序
          ;------- END OF printStr --------------

          ; data area

          msgHello db 'Hello World!',0          ; 以物理 0結束
          msgMore  db 'Wow,my FIRST boot sector!',0
          fixLine  db 13,10,0   ; 回車,換行的ASCII碼

          ; 引導程序必須為512字節,不用的地方以0填充
            times 510-($-$$) db 0            ; $表示程序當前位置,$$表示程序開始位置,由編譯器自動計算
           
          BOOT_SIGN     DW 0xAA55            ; 最后兩個字節為引導標志55AA

          ;--------------------------- End of this programme --------------------------------------

          編譯成功之后,會生成一個512字節的boot.bin,用Winimage創建一個新的軟盤,在“Options(選項)”菜單里,"Winimage mode selection ..." 選擇“WinImage Professional mode(專家模式)”(如果不選專家模式,將不能進行引導扇區的編輯),之后,"Image-> Boot Sector Properties"(映像->引導扇區屬性)中,將引導扇區改為你剛才編譯的程序,保存,用Vmware/Qemu/Bochs之類的虛擬機工具試試你的啟動盤吧!引導成功

          發揮你的想像力,讓你的引導程序實現更多的功能!

          -----------------------------------------------------------

          E-mean X.
          April,03,2005

          轉載請說明作者及出處


          閱讀全文(787) | 回復(5) | 引用(24)
           


          回復:[原創] 操作系統DIY - 啟動你的計
          xemean發表評論于2005-8-15 19:59:11

          文件系統基本上可認為是文件在磁盤上的組織形式,由操作系統管理文件系統,比如MS$系統就用過FAT12、FAT16、FAT32、NTFS...,Linux有EXT等等,這東西不是幾個字就可以說清楚的,還需要看相關的資料。

          操作系統基于文件系統來管理文件,比如讀、寫和修改文件,磁盤從物理上以CHS來定位文件(目前大硬盤有LBA模式),我們在應用中當然不可能通過CHS來定位文件,應用中,我們通過一個路徑來標識一個文件,比如c:\boot.ini、/boot/grub/grub.conf,這是文件系統的一個基本功能。


          個人主頁 | 引用 | 返回
           


          回復:[原創] 操作系統DIY - 啟動你的計
          11(游客)發表評論于2005-7-9 11:54:21
          我想問的就是說文件系統是什么概念呢?引導程序原理我是看懂了 請指教

          個人主頁 | 引用 | 返回
           


          回復:[原創] 操作系統DIY - 啟動你的計
          你好(游客)發表評論于2005-7-9 11:30:16

          你們這么一回 我有點暈了 這里可以去除FAT12的文件系統嗎? 文件系統啟到什么作用?我有點把文件系統和引導程序弄混了,還請指教!

          ;===========================================================================
          bsOEM       db "ExOS0.01"               ; OEM String,任意你喜歡的8字節ASCII碼
          bsSectSize  dw 512                      ; Bytes per sector
          bsClustSize db 1                        ; Sectors per cluster
          bsRessect   dw 1                        ; # of reserved sectors
          bsFatCnt    db 2                        ; # of fat copies
          bsRootSize  dw 224                      ; size of root directory
          bsTotalSect dw 2880                     ; total # of sectors if < 32 meg
          bsMedia     db 0xF0                     ; Media Descriptor
          bsFatSize   dw 9                        ; Size of each FAT
          bsTrackSect dw 18                       ; Sectors per track
          bsHeadCnt   dw 2                        ; number of read-write heads
          bsHidenSect dd 0                        ; number of hidden sectors
          bsHugeSect  dd 0                        ; if bsTotalSect is 0 this value is
                                                  ; the number of sectors
          bsBootDrv   db 0                        ; holds drive that the bs came from
          bsReserv    db 0                        ; not used for anything
          bsBootSign  db 29h                      ; boot signature 29h
          bsVolID     dd 0                        ; Disk volume ID also used for temp
                                                  ; sector # / # sectors to load
          bsVoLabel   db "NO NAME    "            ; Volume Label
          bsFSType    db "FAT12   "               ; File System type <- FAT 12文件系統
          ;===========================================================================

          您這一段是干什么用的? 還有我有個問題文件系統是實質存在?還是我們邏輯存在的?由誰管理呢?我看了很多天這文章和其他東西。搞不清楚~還請多多指教!


          個人主頁 | 引用 | 返回
           


          回復:[原創] 操作系統DIY - 啟動你的計
          xemean發表評論于2005-4-8 20:42:31

          To WY.lslrt:

          呵呵,的確,我忽略了這一點。

          謝謝提醒。


          個人主頁 | 引用 | 返回
           


          回復:[原創] 操作系統DIY - 啟動你的計
          WY.lslrt(游客)發表評論于2005-4-8 18:27:08

          小謝:

            硬盤的引導代碼不能是510字節吧,因為從

          0x1BE-0x1FD是硬盤的基本分區表啊,這可是64字節啊

          posted on 2005-09-14 00:22 春雷的博客 閱讀(478) 評論(1)  編輯  收藏

          評論

          # re: [開發教程][原創] 操作系統DIY - 啟動你的計算機 2008-10-06 01:33 思維機器

          原來也有同樣的愛好者!

          我也寫過。。。很簡單的功能
          沒有用什么工具,資料也不足,只能從軟盤啟動。
          還需要寫保護模式下的代碼編譯程序。。。。巨大的工程。。。沒時間。。沒精力,更沒希望。
          大家多努力
            回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 勃利县| 柳林县| 嵊泗县| 芜湖市| 肥东县| 阿瓦提县| 襄垣县| 会东县| 平顶山市| 吉木乃县| 扬州市| 忻州市| 宝丰县| 防城港市| 布尔津县| 旬邑县| 延庆县| 库伦旗| 天祝| 朝阳县| 蒙山县| 嘉鱼县| 新建县| 皮山县| 会泽县| 东平县| 久治县| 封开县| 临城县| 榆中县| 伊金霍洛旗| 大余县| 贡山| 新巴尔虎左旗| 五寨县| 滨海县| 南乐县| 宜兰市| 张北县| 高淳县| 丰县|