Linux0.00 “boot.s” 程式詳解
/*程式描述: ; boot.s程式編譯出的程式碼共512位元組,將被存放在軟盤映像檔案的第一個扇區中。PC在加電啟動時, ; BIOS程式會把啟動盤上第一個扇區載入到實體記憶體0x7c00位置開始處, ; 然後跳轉到0x7c00處開始執行boot.s程式程式碼。 ; 本程式(boot.s程式)將核心程式碼(head.s程式碼)載入到0x10000處,然後再移動到0x0處0, ; 注意;載入到0x0處是為了設定GDT表時可以簡單一些,因而也可以讓head.s程式儘量短一些, ; 但不能一開始就載入到0x0處是因為載入操作需要使用BIOS提供的中斷過程,而BIOS使用的 ; 中斷向量表正處於記憶體0開始的地方,並且在記憶體1KB開始處是BIOS程式使用的資料區,所以 ; 若直接將head程式碼加載於此將導致BIOS中斷過程不能正常執行。 ; 最後進入保護模式,並轉到0x0處繼續執行。 */ BOOTSEG = 0x07c0 /*前面講到PC加電啟動時會載入本程式到0x7c00處,那為什麼這裡卻是0x7c0,而不 是0x7c00呢,因為8086CPU剛啟動時是處在實地址模式,真實模式下最多定址1M, 並將1MB儲存空間分成許多邏輯段,每個段的長度被固定為64K。這樣每個儲存 單元就可以用“段基地址+段內偏移地址”表示。段基地址由16位段暫存器 值左移4位表達,段內偏移表示相對於某個段起始位置的偏移量。所以這裡的 0x07c0實際上是段基地址。 */ SYSSEG = 0x1000 //將head.s加載於此(這裡為什麼是0x1000而不是0x10000原因同上) SYSLEN = 17 /*核心佔用的最大磁碟扇區數,為了簡化程式,這裡只能載入長度不超過16個扇區 的核心,這個作為BIOS的讀扇區功能的引數。問:既然僅限制16個扇區,為何以 17作為讀入扇區數? 其實這裡設定成16系統也能照常執行,多拷貝一個扇區可 能出於安全考慮。 */ entry start //這個的作用是什麼?彙編器彙編時必須有一個start指明入口地址,否則出現彙編錯誤 start: jmpi go, #BOOTSEG /*jmpi是段間跳轉指令,執行的結果是CS暫存器值變為0x7c0,接下來執 行“BOOTSEG:go”處的指令。 為什麼需要這句話呢?不寫不也是從下 面順序執行嗎? 答:剛開機時所有段暫存器(包括CS)的值為0,資料傳 送指令是不能把資料傳送給CS的,因為CS是程式碼段暫存器,CS如果被修 改程式就無法執行。所以必須用jmpi把cs改為0x7c0。 */ go: mov ax, cs //ax是屬於通用暫存器之一的累加暫存器 mov ds, ax mov ss, ax /*讓兩個段暫存器ds和ss指向0x7c0段,問:1.為何需要讓這兩個段寄存 器指向這裡? 2.為何要通過ax間接傳遞資料而不能直接賦值呢?答: 1.這裡是為了讓DS和SS指向和程式碼段一致的段,ss裡面存放堆疊段的 段地址,sp存放偏移地址,實體地址=ss* 10H+ sp。這樣結合下面一 句,堆疊從實體地址0x7c00+0x400開始,留1K的程式碼空間 2. 80x86 中規定不能對段暫存器(CS,DS等)直接給立即數 */ mov sp, #0x400 /*設定臨時棧指標。其值大於程式末端並有一定空間即可。問:1.為何需要 一個臨時棧指標? 2.這個值怎麼定,程式末端在哪裡如何計算?1.中斷 需要使用到堆疊 2.8086堆疊的生長方向為向下增長。boot.s佔用512位元組 ,這裡設定成遠大於512的任意值就可以。 */ //現在載入核心程式碼(head.s程式)至0x10000開始處 load_system: /*問:標號有沒有實際作用?標號指明其所在位置的地址 首先介紹一下BIOS的0x13的0x02號功能 BIOS INT 0x13的0x02號功能 - 讀扇區 INT 0x13/AH=0x02 - 將磁碟上的扇區讀入記憶體 AH = 0x02 AL = 要讀入的扇區數 CH = 柱面(磁軌)號的低8位 CL = 位7、6是柱面(磁軌號)高2位,位5-0是讀入的起始扇區號(從1計, 第一扇區存放的是boot.s,第二扇區開始放的是head.s,這裡要 讀的是head.s所以從第二個扇區開始讀) DH = 磁頭號 DL = 驅動器號 ES:BX = 緩衝區(用於儲存讀入扇區)的位置 返回值: AH = 狀態碼 AL = 讀到的扇區數 CF = 失敗為1,成功為0 */ mov ch, #0x00 mov cl, #0x02 /*問:為什麼是載入2號扇區?答:因為磁碟的第一扇區放置的即是本程式 (引導啟動程式boot.s),而緊鄰的第二扇區開始則放置核心程式碼head.s 。扇區號從1開始計算。 */ mov dh, #0x00 mov dl, #0x00 //問:驅動器是指什麼?這裡的驅動器號是0,表示floppya,即第一個軟盤驅動器。 mov ax, #SYSSEG /*不能直接執行mov es, #SYSSEG,編譯時會出現illegal immediate mode 錯誤,因為80x86中規定不能對段暫存器(CS,DS等)直接給值/立即數 */ mov es, ax xor bx, bx //將核心放置於1000:0000位置處 mov ah, #0x02 mov al, #SYSLEN int 0x13 //設定好各項引數後即可呼叫BIOS的0x13功能 jnc ok_load //jnc(jump not c)是一跳轉指令,當進位標記C為0時跳轉,為1時執行後面的指令 die: jmp die //死迴圈 /*到目前為止我們已將核心程式碼從磁碟讀入到記憶體中指定位置了,下面就開始將核心 程式碼轉移到0x0這個記憶體開始位置。共移動8K位元組((16個扇區*512B/每扇區)/1024=8KB)。 */ ok_load: cli /*關中斷 問:為何在開始移動時要關中斷,是為了防止什麼事件的發生嗎? 若不關會怎樣? 在搬移之前先介紹一下REP指令及MOVW指令 REP:重複字首,字串操作本身每次只處理一個記憶體值,但如果使用重複前 綴的話,該指令就會使用ECX作為計數器進行重複。換句話說,就是可以用一 條指令處理整個陣列。 MOVW:將DS:SI(源變址暫存器)的內容送至ES(附加段資料暫存器):DI (目的變址暫存器),是複製過去,原來的程式碼還在。 附:ES和DS的功能相同,程式中設有多個數據段時,可以選用ES暫存器。一般 在串處理時用得比較多。比如將一段記憶體空間儲存的資料複製到另一段空間,可 以分別設定DS:SI指向源儲存資料的地址,ES:DI指向目的儲存資料的地址 */ mov ax, #SYSSEG //移動開始位置:DS:SI=0x1000:0;目的位置:ES:DI=0:0 mov ds, ax xor ax, ax mov es, ax mov cx, #0x1000 //設定共移動4K次,每次1個字(即移動16個扇區的程式碼)。 sub si, si sub di, di rep movw //執行重複移動指令 //載入IDT和GDT基地址暫存器IDTR和GDTR mov ax, #BOOTSEG mov ds, ax /*讓DS重新指向0x7c0段(問:1.不一定要讓資料段指向這個位置吧? 答:這裡必 須讓ds重新指向0x07c0段,因為lidt和lgdt隱含的完整格式上是ds:idt_operand和 ds:gdt_operand,會在ds:operand這個位置去尋找它們的六位元組運算元。2.這時 的情況是不是:0x0-0x2000:簡單核心的程式碼區;0x7c00:資料段起始地址; */ lidt idt_48 //載入IDTR。6位元組運算元:2位元組表長度,4位元組線性基地址 lgdt gdt_48 //載入GDTR。6位元組運算元:2位元組表長度,4位元組線性基地址 /*設定好了中斷描述符表IDT和全域性描述符表GDT,並且載入好IDTR和GDTR後,準備進入保護模式 設定控制暫存器CR0(即機器狀態字),進入保護模式。段選擇符值8對應GDT表中第2個段描述符 控制暫存器(CR0、CR1、CR2和CR3)用於控制和確定處理器的操作模式以及當前執行任務的特性 CR0中含有控制處理器操作模式和狀態的系統控制標誌 CR1保留不用 CR2含有導致頁錯誤的線性地址 CR3含有頁目錄表實體記憶體基地址(因此該暫存器也被稱為頁目錄基地址暫存器PDBR) */ mov ax, #0x0001 //(運算元的第四位是0x1=0001,將傳給CR0) /*先介紹一下LMSW指令:LMSW: Load Machine Status Word(置處理器狀態字) 只有運算元的低4 位被存入CR0,只有PE(位0),MP(位1)和EM(位2)和TS(位3)被改寫,CR0其他位不受影響。 */ lmsw ax //設定CR0,進入保護模式。 /*先介紹下JMPI指令(段間跳轉指令),在真實模式下JMPI B, A 是跳到以A為段基地址,以B為偏 移地址處執行,在保護式下JMPI B,A是跳轉到以A為段選擇符,偏移為B處執行。JMP是段內的跳轉 */ jmpi 0, 8 //然後跳轉至段選擇符指定的段中,偏移0處 /*注意此時段值已是段選擇符。該段的線性基地址是0。 這個8是怎麼來的?這個8(實際是 0x0008 ,二進位制:0000000000001 0 00)是段選擇符,由 段選擇符的定義可知,該選擇符選擇的是RPL為0,索引為1的GDT描述符,前面的lgdt指令已 經在GDTR暫存器中存放了GDT表的位置跟長度,每個段描述符固定佔用8位元組,所以根據索引 值就可以找到GDT表中的段描述1,可以看到該段基地址是0x0000000,加上偏移值0,由於這 裡沒有開啟分頁保護,所以是跳到實體地址0處執行。 */ //下面是全域性描述符表GDT的內容。其中包含3個段描述符。第1個不用,另2個是程式碼和資料段描述符 gdt: .word 0,0,0,0 //段描述符0,不用。每個描述符項佔8位元組。 .word 0x07FF //段描述符1,段限長8M,(2048*4096 = 8M) .word 0x0000 //段基地址是0x00000000 .word 0x9A00 //可讀可執行的程式碼段 .word 0x00C0 //顆粒度:4K .word 0x07FF //段描述符2 .word 0x0000 .word 0x9200 .word 0x00C0 //下面分別是LIDT和LGDT指令的6位元組運算元 idt_48: .word 0 .word 0,0 gdt_48: .word 0x7ff .word 0x7c00+gdt,0 .org 510 /*問:這是什麼?答:.org指令表示以後的內容從510位元組開始存放,下面的AA55是引導 扇區的結束標誌,佔二位元組,這就是為什麼boot.s剛好佔512位元組的原因, 如果該標誌錯誤系統就不能啟動。 */ .word 0xAA55
相關推薦
Linux0.00 “boot.s” 程式詳解
/*程式描述: ; boot.s程式編譯出的程式碼共512位元組,將被存放在軟盤映像檔案的第一個扇區中。PC在加電啟動時, ; BIOS程式會把啟動盤上第一個扇區載入到實體記憶體0x7c00位置開始處, ; 然後跳轉到0x7c
linux0.00 "head.s"程式詳解
// head.s包含32位保護模式初始化設定程式碼、時鐘中斷程式碼、系統呼叫中斷程式碼和兩個任務的程式碼。 // 在初始化完成之後程式移動到任務0開始執行,並在時鐘中斷控制下進行任務0和1之間的切換操作。 LATCH = 119
spring-boot入門程式詳解
1.建立一個普通的maven專案,專案名為boot-learnning 2.在pom.xml新增parent依賴 <parent> <groupId>org.springframework.boot</groupId> <
Spring Boot 之 HelloWorld詳解
www repos lookup dex lns jar nap put epo SpringBoot介紹~<暫時假裝有> 配置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="ht
Spring Boot異常處理詳解
在Spring MVC異常處理詳解中,介紹了Spring MVC的異常處理體系,本文將講解在此基礎上Spring Boot為我們做了哪些工作。下圖列出了Spring Boot中跟MVC異常處理相關的類。 Spring Boot在啟動過程中會根據當前環境進行AutoConfigurat
Flask程式詳解
本文將簡要的介紹Flask的各部分作用,並編寫並執行第一個最簡單的Flask程式。 1. 初始化 所有Flask程式都必須建立一個程式例項。Web伺服器使用一種名為Web伺服器閘道器介面(Web Server Gateway Interface,WSGI)的協議,把接收自客戶端的所有請求
spring boot之配置詳解
spring boot支援的配置檔案 spring boot支援兩種型別的配置檔案,一種是傳統的預設配置檔案application.properties ,還有一種是現在被廣泛推薦使用的YAML檔案。書寫上properties是採用鍵值對的形式來表示,而YAML是以類似大綱的縮排形式,這
第一個SpringMVC程式詳解
建立一個java類: package com.myproject.cn; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org
PyInstaller打包Python程式詳解
PyInstaller可以將Python程式及其依賴項打包到一個包中,使用者可以在不安裝Python直譯器或任何模組的情況下執行打包的可執行程式,PyInstaller已經支援Python2.7和3.3+,可以構建多平臺的應用程式,在Windows平臺中建立可執行的Windows應用程式
大資料篇:Spark入門第一個Spark應用程式詳解:WordCount
任務要求 編寫一個Spark應用程式,對某個檔案中的單詞進行詞頻統計。 備註:本文spark的根目錄名:spark-1.6.3-bin-hadoop2.6 #準備工作 cd /usr/local/spark-1.6.3-bin-hadoop2.6 mkdir mycode
SpringBoot非官方教程 | 第二篇:Spring Boot配置檔案詳解
springboot採納了建立生產就緒Spring應用程式的觀點。 Spring Boot優先於配置的慣例,旨在讓您儘快啟動和執行。在一般情況下,我們不需要做太多的配置就能夠讓spring boot正常執行。在一些特殊的情況下,我們需要做修改一些配置,或者需要有自己的配置屬性。 當我們
Spring boot 配置檔案詳解 (properties 和yml )
從其他框架來看 我們都有自己的配置檔案, hibernate有hbm,mybatis 有properties, 同樣, Spring boot 也有全域性配置檔案。 Springboot使用一個全域性的配置檔案,而且配置檔案的名字是固定的。 有兩種 application.properties
Spring Boot 配置檔案詳解:自定義屬性、隨機數、多環境配置等
相信很多人選擇Spring Boot主要是考慮到它既能兼顧Spring的強大功能,還能實現快速開發的便捷。我們在Spring Boot使用過程中,最直觀的感受就是沒有了原來自己整合Spring應用時繁多的XML配置內容,替代它的是在pom.xml中引入模組化的Starter POMs,其中各個模組都有自己的預
Spring boot 2 -配置詳解
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
在Linux上進行原始碼編譯安裝程式詳解
文章轉載自:http://xuweitao.blog.51cto.com/11761672/1905357 1. 編譯安裝概述 前面兩篇關於程式包管理器的文章談到,無論是使用rpm命令還是yum命令安裝的都是已編譯好的程式包,在整個安裝過程中使用者只需執行一條命令即可完成安裝。這樣帶
SpringBoot學習第二篇:Spring Boot配置檔案詳解
原文首發於:https://www.fangzhipeng.com/springboot/2017/07/11/springboot2-config-file/ 本文出自方誌朋的部落格 springboot採納了建立生產就緒Spring應用程式的觀點。 Spring Boot優先於配置的慣例,旨
Spring Boot配置檔案詳解-ConfigurationProperties和Value優缺點-(轉)好文
文章轉自 http://www.cnblogs.com/itdragon/p/8686554.html Spring Boot提供了兩種常用的配置檔案,分別是properties檔案和yml檔案。他們的作用都是修改Spring Boot自動配置的預設值。相對於properties檔案而言,yml檔
Spring Boot 整合 FreeMarker 詳解案例
一、Springboot 那些事 SpringBoot 很方便的整合 FreeMarker ,DAO 資料庫操作層依舊用的是 Mybatis,本文將會一步一步到來如何整合 FreeMarker 以及配置的詳解 二、執行 springboot-freemarker 工程 1.資
Spring Boot事務管理詳解
什麼是事務? 我們在開發企業應用時,對於業務人員的一個操作實際是對資料讀寫的多步操作的結合。由於資料操作在順序執行的過程中,任何一步操作都有可能發生異常,異常會導致後續操作無法完成,此時由於業務邏輯並未正確的完成,之前成功操作資料的並不可靠,需要在這種情況下進行回退。 事務的作用就是為了
Linux從原始碼編譯安裝程式詳解
1.原始碼編譯概述 1.1 使用原始碼安裝軟體的優點: 獲得最新的軟體版本,及時修復bug 根據使用者需要,靈活定製軟體功能 1.2 應用場合舉例 安裝較新版本的應用程式時 當前安裝的程式無法滿足需要時 需要為應用程式新增新的功能時