日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

实验1前篇——BIOS编程空间

發(fā)布時(shí)間:2023/12/16 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实验1前篇——BIOS编程空间 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
???? ?從此篇開始更多的注重技術(shù)細(xì)節(jié)了。細(xì)節(jié)決定成敗的故事太多了,而且對(duì)于編程者肯定都有這樣的經(jīng)歷——自信滿滿的認(rèn)為自己寫得程序天衣無縫,但是當(dāng)運(yùn)行調(diào)試之后,才發(fā)現(xiàn)bug無處不在,更可氣的是很多的bug卻是因?yàn)檎Z(yǔ)法細(xì)節(jié)或者指尖上的失誤導(dǎo)致。而且編碼效率的提升,更多的是建立在已經(jīng)存在的可信代碼的基礎(chǔ)上,而可信代碼卻是經(jīng)歷過無數(shù)次的折騰的結(jié)晶。

?????? 實(shí)驗(yàn)1的內(nèi)容是啟動(dòng)PC系統(tǒng)”——一個(gè)從開機(jī)到運(yùn)行到OS的流程;看似一個(gè)很復(fù)雜的流程,為了很好的解剖這樣的流程,需要充分的知識(shí)準(zhǔn)備,而且更重要的是從代碼的角度去解釋該過程。所以我們將這一篇的內(nèi)容定位與介紹一些概念與模擬代碼,保證理解過程的順利。換句話說,如果在理解實(shí)驗(yàn)1的內(nèi)容有什么問題,可以參考該篇給出的內(nèi)容或者相關(guān)資源。

?????? 本篇主要通過兩個(gè)部分來做出詳細(xì)的介紹:其一為BIOS編程空間;其一為C與匯編的互調(diào)。

一)BIOS編程空間

?????? 這里有一個(gè)很陌生的名詞——編程空間,其實(shí),這是我對(duì)編程環(huán)境的一個(gè)定義,一般用編程環(huán)境來描述,但是它強(qiáng)調(diào)的是編碼的工具與使用的api等概念;但是用編碼空間來代替它,因?yàn)樗粌H僅包含這些內(nèi)容,更多的是強(qiáng)調(diào)編程時(shí)更關(guān)心其代碼運(yùn)行的環(huán)境(內(nèi)存空間,處理器狀態(tài),外設(shè)的資源使用),而且是在一個(gè)固定的環(huán)境中。

??????? 對(duì)于BIOS的編程空間,我們關(guān)注的點(diǎn)主要有如下幾個(gè)方面:

???1.處理器的狀態(tài)

????寄存器的長(zhǎng)度為16位,處于8086的處理器狀態(tài),詳情參考《64-ia-32-architectures-software-developer-manual-325462.pdf》20.1REAL-ADDRESS?MODE

???????2.內(nèi)存的使用

??? 內(nèi)存空間為0-1M的連續(xù)空間,地址訪問方式為(DS<<4|BX);詳情參考《64-ia-32-architectures-software-developer-manual-325462.pdf》20.1REAL-ADDRESS?MODE

??????? 然而不是1M空間都能被任意使用,所以需要理解內(nèi)存映像——內(nèi)存地址區(qū)域的實(shí)際使用情況:


start?

end?

size?

type?

description?

Low?Memory?(the?first?MiB)?

0x00000000?

0x000003FF?

1?KiB?

RAM?-?partially?unusable?(see?above)?

Real?Mode?IVT?(Interrupt?Vector?Table)?

0x00000400?

0x000004FF?

256?bytes?

RAM?-?partially?unusable?(see?above)?

BDA?(BIOS?data?area)?

0x00000500?

0x00007BFF?

almost?30?KiB?

RAM?(guaranteed?free?for?use)?

Conventional?memory?

0x00007C00?(typical?location)?

0x00007DFF?

512?bytes?

RAM?-?partially?unusable?(see?above)?

Your?OS?BootSector?

0x00007E00?

0x0007FFFF?

480.5?KiB?

RAM?(guaranteed?free?for?use)?

Conventional?memory?

0x00080000?

0x0009FBFF?

approximately?120?KiB,?depending?on?EBDA?size?

RAM?(free?for?use,?if?it?exists)?

Conventional?memory?

0x0009FC00?(typical?location)?

0x0009FFFF?

1?KiB?

RAM?(unusable)?

EBDA?(Extended?BIOS?Data?Area)?

0x000A0000?

0x000FFFFF?

384?KiB?

various?(unusable)?

Video?memory,?ROM?Area?


??????? 由上表可以發(fā)現(xiàn),目前0-0x4FF,0x9FC00-0xfffff這兩段內(nèi)存是被系統(tǒng)占用了,不能被我們編程使用。

?????????3.外設(shè)的使用

???? BIOS對(duì)于外設(shè)資源的使用,主要提供了兩種方式:其一為中斷服務(wù),其二為外設(shè)io地址空間。對(duì)于外設(shè)我們主要關(guān)注點(diǎn)為顯示器,鍵盤,串口,硬盤。

??????? 對(duì)于外設(shè)的使用與控制,我覺得一個(gè)很有用的觀點(diǎn)是來之于《PC內(nèi)幕技術(shù)》——資料的來源:

??????? 大多數(shù)情況下,我首先回顧了一下制造商為子系統(tǒng)提供的ic數(shù)據(jù)源清單,然后仔細(xì)察看這些芯片在標(biāo)準(zhǔn)主板上是如何具體連接的,做到這一點(diǎn)需要用到系統(tǒng)的原理圖,在某些情況下,還要查看系統(tǒng)的電路圖。我也仔細(xì)研究了不同制造商提供的反匯編BIOS代碼,以便在這些較低的層次上考察它們與子系統(tǒng)的聯(lián)系。我還生成了一些測(cè)試程序來檢驗(yàn)?zāi)澄髯酉到y(tǒng)的操作。最后,我才去看那些正式的文檔,包括IBM的技術(shù)參考資料,當(dāng)然它也是許多其他技術(shù)書籍的資料來源。

??????? 上面的一段話對(duì)如何認(rèn)識(shí)與學(xué)習(xí)ic子系統(tǒng)提供了基本而且嚴(yán)謹(jǐn)?shù)牟襟E與方法,很值得我們每個(gè)人向前輩學(xué)習(xí)。也幸好有前輩們的鋪墊,我們只需要在已經(jīng)有的文檔中與代碼中,理解相關(guān)核心而基本的概念,然后使用總結(jié)好的代碼,保證我們能夠?qū)ο到y(tǒng)有更好的理解與實(shí)現(xiàn)。

???? 如下為詳細(xì)的介紹相關(guān)外設(shè)的知識(shí):

???? A)鍵盤——PS/2?keyboards

作為分析的一個(gè)最簡(jiǎn)單的外設(shè)——主要作為輸入設(shè)備,它的控制芯片為Intel?8042?microcontroller。默認(rèn)了qemu是模擬的IBM?PC/XT?Keyboard?的鍵盤按鍵,其掃描碼詳情見:http://www.computer-engineering.org/ps2keyboard/scancodes1.html

系統(tǒng)組織結(jié)構(gòu)圖如下,詳情可見《PC內(nèi)幕》8.1圖:

鍵盤的基本工作原理:鍵盤檢測(cè)到按鍵按下,然后將按鍵掃描碼通過串口發(fā)送給主板的8042,接著被翻譯為系統(tǒng)掃描碼,放入輸出緩存中,最后通過IRQ9給處理器。

??????? 另外,讀取鍵盤按鍵發(fā)送給主板的時(shí)序如下:

????

如上所述,讀取按鍵的方法有兩種,一種就是通過中斷服務(wù)IRQ?9;另一種為通過io指令讀取8042緩存的按鍵值。

如下提供一種通過io指令讀取按鍵的方法——參考8042提供的io口寄存器配置如下表:

????

Port

Read?/??
Write

Function

0x60

Read

Read?Input?Buffer

0x60

Write

Write?Output?Buffer

0x64

Read

Read?Status?Register

0x64

Write

Send?Command

如下為讀取按鍵的代碼示例:

kbRead: 1:in $0x64,%al#讀取通訊狀態(tài)andb %al,0x01#檢測(cè)接收按鍵掃描碼是否okjz 1bin $0x60,%al #讀取鍵值

???? 由以上參考讀取按鍵的流程,在讀取鍵值之前需要讀取按鍵是否準(zhǔn)備好,因?yàn)橛梢粋€(gè)通信的過程。

???????? 如果想進(jìn)一步了解,請(qǐng)參考如下的內(nèi)容:

http://www.computer-engineering.org/ps2keyboard/

http://retired.beyondlogic.org/keyboard/keybrd.htm#1

?? 或者參考《IBM.PC.匯編語(yǔ)言程序設(shè)計(jì)(第五版)完整版》第10章,《PC內(nèi)幕技術(shù)》第8章。

??B)串口——UART

?? 對(duì)于串口的理解,我們可以通過兩種方式去理解,其一是屬于數(shù)據(jù)通信的范疇,數(shù)據(jù)通信一般需要考慮的問題:數(shù)據(jù)(幀)格式(數(shù)據(jù)位序LSB),數(shù)據(jù)傳輸速率,出錯(cuò)控制,流量控制;另外,串口又作為系統(tǒng)的外設(shè),又需要中斷控制,一般由如下芯片實(shí)現(xiàn)其功能:

芯片編號(hào)

描述

8250

基本UART功能支持,最早的串口芯片

8250A/B

比8250更快

16450

8250的改進(jìn),IBM-AT上使用,支持38.4KBPS

16550

在16450基礎(chǔ)上,加入接收與發(fā)送的FIFO

16552

支持2個(gè)16550UART

16C454/16C1450/16C1550

支持4路16550UART,同時(shí)支持程序可控的掉電與重起

16650/17650

支持更多的FIFO

?? 所以根據(jù)如上的描述可以得出串口的屬性:

????? (1)波特率——最小波特率,最大波特率

?? 根據(jù)標(biāo)準(zhǔn)的串口的頻率表,可以得到最大的波特率如下:

串口頻率

1.8432Mhz

2.4546Mhz

最大波特率

115.2?KBPS

153.6?KBPS

?????? 如果設(shè)置其他的波特只需要直接分頻即可。

??? 比如:0x03?=??38,400?BPS

?? (2)數(shù)據(jù)格式——數(shù)據(jù)長(zhǎng)度,字節(jié)序(LSB),終止位,奇偶校驗(yàn)

???????

???? (3)流控——FIFO的支持——常見的模式?jīng)]有使用

???? (4)傳輸狀態(tài)——是否傳輸成功與出錯(cuò)

???? (5)中斷設(shè)置——設(shè)置中斷與查詢中斷

????? 根據(jù)如上的屬性,PC系統(tǒng)給出的寄存器表如下,pc系統(tǒng)最多支持4com

口:

Name?

Base?Address

IRQ

COM?1?

3F8?

4

COM?2?

2F8?

3

COM?3?

3E8?

4

COM?4?

2E8?

3

??????????????????????????????? 默認(rèn)的com口基地址與IRQ

?

Base?Address

DLAB

Read/Write

Abr.?

Register?Name?

+?0

=0

Write

-?

Transmitter?Holding?Buffer?

?

=0

Read

-?

Receiver?Buffer?

?

=1

Read/Write

-?

Divisor?Latch?Low?Byte?

+?1

=0

Read/Write

IER?

Interrupt?Enable?Register?

?

=1

Read/Write

-?

Divisor?Latch?High?Byte?

+?2

-

Read

IIR?

Interrupt?Identification?Register

?

-

Write

FCR?

FIFO?Control?Register?

+?3

-

Read/Write

LCR?

Line?Control?Register?

+?4

-

Read/Write

MCR?

Modem?Control?Register?

+?5

-

Read

LSR?

Line?Status?Register?

+?6

-

Read

MSR?

Modem?Status?Register?

+?7

-

Read/Write

-?

Scratch?Register?

?????????????????????????? 支持默認(rèn)com口寄存器

根據(jù)如上表可以看出一個(gè)寄存器由多種功能,其中由一列為DLAB,為一個(gè)開關(guān)設(shè)置波特率的方式;而DLAB的開關(guān)又在LCR的最高位,具體的每個(gè)參數(shù)功能可以參考如下的地址:

http://byterunner.com/16550.html

另外查詢系統(tǒng)支持的com,可以根據(jù)下表的的內(nèi)存地址讀取相關(guān)的基地址:

Start?Address

Function

0000:0400

COM1's?Base?Address

0000:0402

COM2's?Base?Address

0000:0404

COM3's?Base?Address

0000:0406

COM4's?Base?Address

針對(duì)如上的內(nèi)容解釋可以看出如果要操作串口,有兩種方式,其一為中斷,其二為io指令;一般操作串口的步驟由如下3步:

(1)查詢哪路com能夠被使用,確認(rèn)com的基地址:

movw $0x406,%bx #從com4開始查詢每個(gè)com口是否支持movw $4,%cx check_com:cmpw $0,(%bx)#如果com口的基地址為0,說明該路com口不支持movw (%bx),%ax #讀取com口基地址jne put_com_info next:sub $2,%bxloop check_comjmp 1f

(2)初始化UART的通信狀態(tài):


init_com:OUT_B 0,(PORT1+2) #設(shè)置FCR,FIFO控制為關(guān)OUT_B 0x80,(PORT1 + 3)#開啟DLABOUT_B 0x03,(PORT1 + 0)#設(shè)置最低波特率為38,400 BPSOUT_B 0x00,(PORT1 + 1 ) #設(shè)置最高波特率為115200BPSOUT_B 0x03,(PORT1 + 3) #關(guān)閉DLAB,設(shè)置數(shù)據(jù)位為8位,停止位1位,沒有校驗(yàn)OUT_B 0x01,(PORT1 + 1)#設(shè)置中斷IEROUT_B 0x00,(PORT1 + 4)#關(guān)閉MCRmovw $(PORT1+2),%dx #如下為清楚數(shù)據(jù)緩沖inb %dx,%almovw $(PORT1),%dxinb %dx,%alret

??? (3)發(fā)送串口數(shù)據(jù):


out_char_to_console:1:movw $(PORT1+5),%dx #讀取LSR狀態(tài),是否發(fā)送完畢inb %dx,%alandb %al,0x20 #發(fā)送緩沖為空jz 1bmovb $'a',%almovw $PORT1,%dx outb %al,%dx #發(fā)送數(shù)據(jù)ret??? 如果需要詳細(xì)了解,請(qǐng)參考如下地址:

http://retired.beyondlogic.org/serial/serial.htm

????C)硬盤

對(duì)于硬盤的理解,我們需要了解兩方面的知識(shí):1.子系統(tǒng)構(gòu)造,2.磁盤容量。子系統(tǒng)構(gòu)造會(huì)告訴我們控制硬盤的一些基本概念;理解磁盤容量,可以方便我們?nèi)プx取磁盤數(shù)據(jù)。

(1)子系統(tǒng)構(gòu)造框圖——摘錄于《PC內(nèi)幕技術(shù)》第11章簡(jiǎn)介:

????

????

?????上圖我們可以發(fā)現(xiàn)我們讀取磁盤數(shù)據(jù),需要選擇相關(guān)的驅(qū)動(dòng)器。

???? (2)理解磁盤容量,需要知道磁盤的構(gòu)造:

?????

??????? 由上圖可見硬盤主要是由多個(gè)磁盤構(gòu)成,每個(gè)磁盤有2個(gè)磁頭,每個(gè)磁盤可以分為若干個(gè)磁柱,每個(gè)磁柱又由磁道構(gòu)成,磁道由扇區(qū)構(gòu)成。扇區(qū)為512Byte。所以磁盤容量由如下的公式給出:

??? 磁盤容量?=磁頭數(shù)*磁柱數(shù)*磁道扇區(qū)數(shù)*512Byte。

??? 如上的計(jì)算方法為CHS模式。而CHS模式尋址,只有24位,10位C,8位H,6位S。所以支持的最大容量為:1024*255*64*512B=8GByte.

??? 根據(jù)BIOS的容量限制,可以發(fā)現(xiàn)磁盤的最大容量為8GByte,所以這種描述方法不足以描述磁盤容量,所以目前的磁盤支持邏輯塊尋址(LBA),它將整個(gè)磁盤看作連續(xù)的規(guī)定大小的邏輯塊。LBA支持48位,所以它的最大尋址空間為128PB.

??? 更詳細(xì)的了解可以參考如下博客:

http://blog.csdn.net/haiross/article/details/38659825

??????? 當(dāng)我們了解了以上內(nèi)容之后,對(duì)硬盤有如下兩種操作:

?????? (1)讀取硬盤參數(shù):

???????

movb $0x80,%dl #讀取硬盤,0x80表示硬盤,0x00軟盤movb $0x08,%ah #讀取硬盤參數(shù)int $0x13 #13號(hào)磁盤中斷

如果讀取成功CF0具體磁盤參數(shù)如下:

CHS=(CX[6:15],DH,CL[0-5]).

?DL表示驅(qū)動(dòng)數(shù)

????(2)讀取硬盤數(shù)據(jù):

?? a)通過INT?13?2來進(jìn)行讀取——CHS模式:

disk_2:#讀取mbr到 0:0x800093 movw $0x800,%ax 94 movw %ax,%es95 movw $0x00,%bx96 movb $0x80,%dl97 movb $0x01,%al98 movw $0x01,%cx #讀取第一個(gè)扇區(qū)99 movb $0x00,%dh 100 movb $0x02,%ah #功能2 101 int $0x13 102 mov $0xb4,%ax 103 cmp 0x8000,%ax 104 jnz 1f 105 movb $'y',%al 106 OUT_B0??? b)通過INT?13?0x42來進(jìn)行讀取 —— LBA模式:

?

lba_mode:movw $0x80,%dl #讀取第一個(gè)驅(qū)動(dòng)器xorw %ax, %axmovw %ax, 4(%si)#設(shè)置讀取數(shù)據(jù)的內(nèi)存地址incw %ax/* set the mode to non-zero */movb %al, -1(%si)/* the blocks 讀取的大小 */movw %ax, 2(%si)/* the size and the reserved byte */movw $0x0010, (%si)#設(shè)置包的大小與保留字節(jié)/* the absolute address 設(shè)置讀取開始地址*/movl kernel_sector, %ebxmovl %ebx, 8(%si)movl kernel_sector + 4, %ebxmovl %ebx, 12(%si)/* the segment of buffer address 設(shè)置保存數(shù)據(jù)的段地址*/movw $GRUB_BOOT_MACHINE_BUFFER_SEG, 6(%si)movb $0x42, %ahint $0x13

???? 詳細(xì)解釋如下:

/*

?*?BIOS?call?"INT?0x13?Function?0x42"?to?read?sectors?from?disk?into?memory

?*Call?with%ah?=?0x42

?*%dl?=?drive?number——驅(qū)動(dòng)號(hào),從(0x80+0開始的驅(qū)動(dòng)號(hào)),一般支持兩個(gè)驅(qū)動(dòng)器0x80|0x81.

?*%ds:%si?=?segment:offset?of?disk?address?packet——發(fā)送數(shù)據(jù)參數(shù)包地址

?*Return:

?*%al?=?0x0?on?success;?err?code?on?failure

?*/

數(shù)據(jù)包格式如下:

struct?Disk_Packet{

unsigned?char?Packat_Size;//1?0x10|0x18

unsigned?char?Reserved0;//1

unsigned?short?Read_Size;//2

unsigned?int*?Buf_Addr;//4?[BX:DS]

unsigned?long?Start_Number;//8

};

??? c)通過io口的方式來讀取磁盤數(shù)據(jù):

??

void waitdisk(void) {// wait for disk reaadywhile ((inb(0x1F7) & 0xC0) != 0x40)/* do nothing */; }void readsect(void *dst, uint32_t offset) {// wait for disk to be readywaitdisk();outb(0x1F2, 1); // count = 1outb(0x1F3, offset);outb(0x1F4, offset >> 8);outb(0x1F5, offset >> 16);outb(0x1F6, (offset >> 24) | 0xE0);outb(0x1F7, 0x20); // cmd 0x20 - read sectors// wait for disk to be readywaitdisk();// read a sectorinsl(0x1F0, dst, SECTSIZE/4); }

??? 如果想了解更多,請(qǐng)參考《AT?Attachment?with?Packet?Interface?-?6?(working?draft)》與《PC內(nèi)幕》。

??D)顯示器

??? 對(duì)于顯示器,就更復(fù)雜了。為此我們需要先了解系統(tǒng)的視頻子系統(tǒng)——如下框圖摘錄于《IBM.PC.匯編語(yǔ)言程序設(shè)計(jì)(第五版)完整版》第9章:

???

????? 如上圖可以看出顯示系統(tǒng)的基本原理從視頻顯示區(qū)拿數(shù)據(jù),然后進(jìn)行相關(guān)的處理,最終顯示到顯示器上,所以我們只需要程序去修改視頻顯示區(qū)的數(shù)據(jù)就可以控制顯示器的顯示。而如上顯示原理主要是描述的是文本模式的顯示器工作。對(duì)于文本模式的顯示器,描述每個(gè)字符需要兩個(gè)byte來表示:前一個(gè)byte為字符值,后一個(gè)字符為對(duì)應(yīng)的屬性值對(duì)于這種情況可以查看顯示空間的內(nèi)存。屬性值對(duì)應(yīng)如下表:

說明

背景

前景

屬性

BL(閃爍)????R??G?B

I(高亮顯示)???????R?????????G???????B

7??????????????????6???5???4

3???????????????????????2????????1??????????0

?????? 對(duì)于顯示區(qū)域BIOS給定了固定的地址空間,針對(duì)不同的顯示器有如下3種情況,更詳細(xì)的見表int?13?功能0的表:

??????????A000:[0]?高級(jí)或者復(fù)雜的顯示器

??????????B000:[0]?單色文本

??????????B800:[0]?文本與圖形

?????? 對(duì)于顯示器有兩種操作方式:其一通過中斷顯示數(shù)據(jù),其二,通過將數(shù)據(jù)寫入顯示區(qū)域。對(duì)于“文本模式”的顯示器,還有一個(gè)重要的就是“光標(biāo)”的位置確定。

???? A)查詢系統(tǒng)使用的顯示器?int?13?0f?得到視頻模式

??? 詳細(xì)信息,可以通過bios手冊(cè)查詢得到如下默認(rèn)的CGA(03),如下:

??? 03h?=?T??80x25?8x8???640x200?16??4???B800?CGA,Pcjr,Tandy

??? 如上信息可以知道:

??? 視頻模式為03,且為“文本模式”,支持的字符顯示最大范圍為:80列,25行。每個(gè)字符顯示為8*8的像素,總的屏幕分辨率為640*200.支持16色,最多支持4頁(yè)顯示頁(yè),顯示區(qū)域的開始地址為B8000,支持的顯示器模式為CGA,Pcjr,Tandy。

???B)輸出字符串到屏:

?? (1)通過中斷(int?10h?13h)

?

out_str_to_screen:#輸出字符到屏幕xorw %ax,%ax# movw %cx, %ax#cx->ax,寄存器的需要用% # movw %ax, %ds#初始化數(shù)據(jù)段movw %ax, %es#初始化擴(kuò)展段 #如下位利用BIOS的中斷0x10來實(shí)現(xiàn)輸出字符串到屏幕上 #詳情功能定義可以參考bios手冊(cè) #中斷:int 0x10 #功能號(hào):ah = 0x13,輸出字符串到屏幕 #屬性:es:bp表示輸出的字符串 # cx表示輸出字符串長(zhǎng)度 # dh,dl表示顯示的行與列 #movw $msgstr,%bp#將msgstr的地址放入bp,地址的表示為$movw len, %cx #將字符串的長(zhǎng)度放入cx,標(biāo)志的值直接用標(biāo)識(shí)符movb $0x01, %al #movb $0x01, %bl #字符屬性movb $0x00, %bh #第0頁(yè)movb $0x05, %dh #第5行 movb $0x08, %dl #第8列movb $0x13, %ah # 功能13,輸出字符串int $0x10 #調(diào)用中斷10h

?? (2)直接寫顯示區(qū)域

????

print_str:#通過直接寫顯示區(qū)域的方式,輸出字符xorw %bx,%bxmovb $'T',%almovb $0xCE,%ahmovw $0xB800,%cxmovw %cx,%dsmovw %ax,(5*80*2+19*2)(%bx)#第5行第24個(gè)字符

??? C)獲取與修改光標(biāo)位置:

? (1)通過中斷(int?10h?03h):

read_cursor: #讀取光標(biāo)位置movb $0x0,%bhmovb $0x03,%ahint $0x10

? (2)通過io指令讀取:


set_cursor: #設(shè)置光標(biāo)OUT_B 14,0x3D4 #切換到第5行第24個(gè)字符的位置OUT_B (5*80+19)/256,0x3D5OUT_B 15,0x3D4OUT_B (5*80+19)%256,0x3D5? 更詳細(xì)的介紹可以參考如下網(wǎng)址,或者參考《PC內(nèi)幕》或者《IBM.PC.匯編語(yǔ)言程序設(shè)計(jì)(第五版)完整版》:

?????http://www.osdever.net/FreeVGA/home.htm


??

????????對(duì)于第1,2點(diǎn)的詳細(xì)了解,我們才能知道如何編寫代碼,然后執(zhí)行之。而BIOS的編程之后的代碼執(zhí)行是在mbr中,所以我們需要搭建bios實(shí)驗(yàn)環(huán)境。然后調(diào)試我們的外設(shè)的相關(guān)代碼。所以我們的最初代碼執(zhí)行空間也只有512Btye(0x7C00-0x7DFF),如果要使用更多的代碼,需要將它們放到磁盤的后續(xù)分區(qū),然后被加載到內(nèi)存中,才能使用。對(duì)于如上描述可以參考我博客的附件資源,其中包含了所有的實(shí)現(xiàn),方便理解。

????另外推薦一份bios的參考手冊(cè),絕對(duì)詳細(xì):

http://www.cs.cmu.edu/~ralf/files.html

??? 關(guān)于中斷的參考手冊(cè):

http://www.htl-steyr.ac.at/~morg/pcinfo/hardware/interrupts/inte1at0.htm


??二)C與匯編的互調(diào)

? 在系統(tǒng)一上電運(yùn)行的代碼肯定是匯編語(yǔ)言,等到將c語(yǔ)言運(yùn)行環(huán)境創(chuàng)建好了之后才能運(yùn)行之。所以需要了解如下幾個(gè)方面的知識(shí):

?? 1.首先匯編代碼如何被執(zhí)行

?? 根據(jù)上一節(jié)描述,我們寫的代碼會(huì)放在mbr里,當(dāng)然如果突破了mbr的限制,其他代碼可以放到硬盤的其他扇區(qū)。在mbr的代碼會(huì)被自動(dòng)加載的0x7C00中執(zhí)行,所以我們需要將我們的代碼鏈接到0x7C00,查看makefile會(huì)發(fā)現(xiàn)可以這樣實(shí)現(xiàn):

?? A.直接鏈接生成mbr


boot: boot.o ld --oformat binary -N -Ttext 0x7c00 -o $@ $< #生成mbr扇區(qū),鏈接地址為0x7C00???

? B.鏈接成elf文件后,再轉(zhuǎn)換:

?

read_sector.out:read_sector.old -N -Ttext 0x8400 -o $@.bak $< -e readsect -m elf_i386 #這里是鏈接到地址0x8400,進(jìn)入點(diǎn)為readsectobjcopy -S -O binary -j .text $@.bak $@#將生成read_sector.out.bak 轉(zhuǎn)換成 read_sector.out。

??? 方法2比方法1的優(yōu)勢(shì)是:a.文件更小,b.生成的elf文件可以被反匯編分析。

? 方法1的優(yōu)勢(shì):簡(jiǎn)單。

?? 關(guān)于mbr的詳細(xì)介紹可以參考百度百科:

http://baike.baidu.com/link?url=sQhyg1wSqI1n3JgBuueAkh9NUlQ6iCG5a0HsfVexr4Ky3gwDfgxYBzsMwGZTcCzOqom8wfuxG62WxNYsP6WB6zOcdvocdfRtSUnKEkVC0Ji

? 它的解析,有附件的一個(gè)c語(yǔ)言文件。獲取本機(jī)系統(tǒng)的mbr可以用如下命令:

sudo dd if=/dev/sda of=mbr bs=512 count=1
? 2.匯編如何調(diào)用c語(yǔ)言:

? 匯編為了調(diào)用c語(yǔ)言,需要做兩步工作,第一創(chuàng)建c語(yǔ)言運(yùn)行環(huán)境,第二調(diào)用c語(yǔ)言入口代碼。

?? a)創(chuàng)建c運(yùn)行環(huán)境:

???因?yàn)閏語(yǔ)言的基本結(jié)構(gòu)是基于堆棧的,所以首先要?jiǎng)?chuàng)建堆棧:

init_stack:xorw %ax,%axmovw %ax,%es #設(shè)置堆棧段movw $0x7c00,%sp #設(shè)置棧頂?? c語(yǔ)言調(diào)用過程中肯定會(huì)讀寫全局?jǐn)?shù)據(jù),所以需要設(shè)置對(duì)應(yīng)的數(shù)據(jù)段:

xorw %bp,%bp #清除bp,因?yàn)樗鼤?huì)被c語(yǔ)言用于棧幀的開始指向。movw %bp,%ds #設(shè)置數(shù)據(jù)段movw %bp,%es #設(shè)置擴(kuò)展段?? b)調(diào)用c語(yǔ)言,傳入?yún)?shù),然后調(diào)用對(duì)應(yīng)的地址就可以了:

pushl $0 #設(shè)置第2個(gè)參數(shù)pushl $0x8000 #設(shè)置第一個(gè)參數(shù)calll 0x843b #調(diào)用c語(yǔ)言入口的函數(shù)地址?? 注意傳遞參數(shù)的順序是,從右到左。

?? 3.c語(yǔ)言如何調(diào)用匯編語(yǔ)言:

?? 通過AT&T內(nèi)嵌匯編語(yǔ)法調(diào)用:

static __inline void outb(int port, uint8_t data) {__asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); } static __inline uint8_t inb(int port) {uint8_t data;__asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));return data; }??? C語(yǔ)言使用inline的方法,聲明函數(shù)為內(nèi)斂:

static __inline uint8_t inb(int port) <strong>__attribute__((always_inline))</strong>; static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline)); static __inline void outb(int port, uint8_t data) __attribute__((always_inline));

?? 4.匯編語(yǔ)言編程的技術(shù)總結(jié)

????? 這里講的匯編語(yǔ)言主要是unix標(biāo)準(zhǔn)下的AT&T語(yǔ)法,簡(jiǎn)單來說與Intel的語(yǔ)法有差別的地方與特定的偽指令支持,為什么需要了解AT&T匯編呢?因?yàn)樵趌inux平臺(tái)上,甚至Unix下,都適用,它與硬件平臺(tái)無關(guān),所以適用性很強(qiáng)。

? a.支持的指令格式,操作數(shù)與Intel匯編相反,比如:

? Intel?:mov?eax,?ebx?#ebx->(賦值給)eax

? AT&T??:mov?%ebx,%eax

? 編譯器會(huì)檢測(cè)操作順序,如果不能匹配,則出錯(cuò)。

? b.Intel的指令,AT&T都支持,所以對(duì)于一些不了解的指令,可以參考Intel的相關(guān)技術(shù)手冊(cè)。

? c.操作數(shù)的表示格式

? 寄存器前需要添加%

? 立即數(shù)需要添加$

? 默認(rèn)常數(shù)為地址

??? d.對(duì)宏的支持:

.macro OUT_B v pa #定義宏——將v輸出到端口pa,參數(shù)為v,pa#通過宏定義,將參數(shù)v轉(zhuǎn)化為簡(jiǎn)單的表達(dá),換句話說,在宏定義中,參數(shù)的引用為\v。 #define V \v #define PA \pamovb $(V),%al #將V當(dāng)作立即數(shù)使用movw $(PA),%dxoutb %al,%dx .endm

????? f.運(yùn)行數(shù)據(jù)的保存

???? 因?yàn)?span style="font-family:Times New Roman">intel只有8個(gè)寄存器EAX,EBX,?ECX,?EDX,?ESI,?EDIESPEBP可用,而且很多時(shí)候都是受限的——即特定的寄存器有特定的用途,比如:相對(duì)尋址只有用EBX。所以,寄存器的資源是不夠的,需要用堆棧來保存:



xorw %ax,%axmovw %ax,%dspush %ds #保存dsmovw $0x40,%axmovw %ax,%dsmovw $0x47,%bxmovb (%bx),%alpop %ds #恢復(fù)ds??

??? g.對(duì)地址空間的使用:


x: .byte 'x'y: .int 0x1234z: .word 0x2345str: .ascii “Hello world!\0”str1: .asciz “Hello world!”.的使用,表示當(dāng)前地址?

???? 如上的內(nèi)容可以參考《gas_manual-unix匯編》與我附件的代碼。


??? 一葉說:終于寫完了,內(nèi)容太多了,而且需要一步步謹(jǐn)慎的驗(yàn)證;如上內(nèi)容只是截取了主要的知識(shí)介紹,對(duì)我們后期理解系統(tǒng)的運(yùn)行流程與實(shí)現(xiàn)相關(guān)代碼有幫助;請(qǐng)理解它們,請(qǐng)調(diào)試它們。如果需要更進(jìn)一步了解相關(guān)內(nèi)容,請(qǐng)參考詳實(shí)附件,這樣對(duì)理解整個(gè)系統(tǒng)與相關(guān)軟件的工作原理更有意義。最后還要感謝前輩們的知識(shí)總結(jié),也希望后來的我們能夠站在它們的肩膀上,爬得更高。



總結(jié)

以上是生活随笔為你收集整理的实验1前篇——BIOS编程空间的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。