生活随笔
收集整理的這篇文章主要介紹了
babyos (三)——利用BIOS INT 0x13读取软盘
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
注:以下程序為原創,若發現任何BUG,歡迎指正;若有問題,歡迎交流;權利歸原作者所有,若轉載,請注明出處;若能有益于一二訪客,幸甚。
昨天學習了VGA顯示的一些東西,今天準備學習一下讀取軟盤的知識。
1.babyos將使用的引導過程
1)系統上電或reset時,處理器執行一些初始化,CPU處于實模式
2)處理器會執行一個位于已知位置處的代碼,PC中這個位置位于BIOS,它保存在主板上的閃存中
3)控制權交給BIOS后,它尋找一個可引導的設備(軟盤、硬盤等),BIOS讀取引導扇區(512字節)到內存0x7c00處,并跳轉到該地址執行
4)引導扇區中存放的指令可以使用BIOS中斷,它將會讀取軟盤中內核部分到一個臨時地址(如0x10000,不覆蓋0x7c00處的boot代碼即可)
5)將內核前512字節(load.s, 它主要負責將內核剩余部分拷貝到load.s后面)移動到0x0處,將GDT拷貝到0x80000處。為什么不一次全部將內核放到0x0處呢?因為內核可能較大,會覆蓋掉0x7c00處的代碼。
6)開啟A20總線,置位CR0的bit 0,開啟保護模式,加載GDT到GDTR,跳轉到GDT第二項(第一項為空GDT),即load.s處執行
7)load.s將內核剩余部分移動到load.s后面,即0x200開始的地址處。然后執行初始化代碼。
8)初始化代碼,至此系統啟動成功。
所以首當其沖的問題就是如何讀軟盤。
2.軟盤的結構
3.5寸1.44M 軟盤,如圖floppy_struct.png 所示,有兩個磁頭,正反兩面各一個;80個磁道(即80個圓圈);每個磁道有18個扇區;每個扇區為512字節。
容量 = 512字節/扇區 * 2面 * 80磁道(柱面)/面 * 18扇區/磁道 = 1440 KB
磁頭,即面:編號[0, 1]
80個磁道,即柱面(圓圈):編號[0, 79]
18個扇區:編號[1, 18]
相對扇區號[0, 2879]:
相對扇區號按照柱面排序,即從最外頭的圓圈到最里頭的圓圈。
0柱面正面(即磁頭號為0)的1-18扇區為0-17號相對扇區,0柱面反面(即磁頭號為2)的1-18扇區為18-35號相對扇區,然后是1柱面,2柱面,直到79柱面。如下:
[cpp] view plaincopyprint?
0柱面,0磁頭,1扇區?????????0??0柱面,0磁頭,2扇區?????????1??……??0柱面,0磁頭,18扇區????????17??0柱面,1磁頭,1扇區?????????18??……??0柱面,1磁頭,18扇區????????35??1柱面,0磁頭,1扇區?????????36??……??1柱面,0磁頭,18扇區????????53??1柱面,1磁頭,1扇區?????????54??……??1柱面,1磁頭,18扇區????????71??2柱面,0磁頭,1扇區?????????72??……??
3.利用BIOS 中斷讀取軟盤
[cpp] view plaincopyprint?
-------------------------------------------------------------------??????????????????????INT?0x13,功能02??-----------------------------------------------------------??參數:??????AH??????02??????AL??????讀取扇區數??????CH??????柱面[0,?79]??????CL??????扇區[1,?18]??????DH??????磁頭[0,?1]??????DL??????驅動器(0x0?~?0x7f表示軟盤,0x80?~?0xff表示硬盤)??????ES:BX???緩沖區地址,即數據讀到這里??返回值:??????CF?=?0表示操作成功,此時AH=0,AL=傳輸的扇區數??????CF?=?1即carry位置位(可用JC表示跳轉)表示操作失敗,AH=狀態代碼??--------------------------------------------------------------------??
4.相對扇區號的計算
1)知道柱面號,磁頭號,扇區號計算相對扇區號
由上面可知0號柱面包含了相對扇區號[0,35],1號柱面包含相對扇區號[36,71],依次類推。
設相對扇區號為N,則
柱面號CH = N / 36;
令x = N % 36;
則x范圍為[0,35],其中[0,17] 為磁頭號0, [18,35]為磁頭號1.
則磁頭號DH = x / 18;
零y = x % 18; y范圍[0, 17]
則扇區號CL = y + 1。
2)知道相對扇區號,計算柱面號、磁頭號、扇區號
N = 36*CH + 18*DH + CL;
由此式子,也可計算:
CH = N / 36
DH = (N % 36) / 18
CL = (N % 36) % 18 + 1
5.讀取一個扇區
實驗:將一些數據寫入軟盤的第二個扇區(第一個扇區是引導扇區),然后用BIOS 中斷讀取該扇區的數據,并顯示在屏幕上。然后看讀取的數據是否與寫入的數據相同。注:第二個扇區相對扇區號為1.
[cpp] view plaincopyprint?
寫數據的C代碼:???????????#include?<stdio.h>??#include?<string.h>????int?main()??{??????FILE?*fp;??????fp?=?fopen("./data",?"wb");????????????int?i;??????char?*str?=?"baby?os,?guzhoudiaoke@126.com?";??????int?len?=?strlen(str);????????????for?(i?=?0;?i?<?len;?i++)??????????fprintf(fp,?"%c",?str[i]);????????for?(i?=?512-len;?i?>?0;?i--)??????????fprintf(fp,?"%c",?i?%?26?+?'A');????????return?0;??}????匯編代碼:??#?This?program?draws?color?pixels?at?mode?0x13??#?2012-12-26?01:31??#?guzhoudiaoke@126.com????.include?"boot.inc"????.section?.text??.global?_start??.code16????_start:??????jmp?????main????#--------------------------------------------------------------??#?清屏函數:??#???設置屏幕背景色,調色板的索引0指代的顏色為背景色??clear_screen:???????????????#?清屏函數??????movb????$0x06,??%ah?????#?功能號0x06??????movb????$0,?????%al?????#?上卷全部行,即清屏??????movb????$0,?????%ch?????#?左上角行??????movb????$0,?????%ch?????#?左上角列????????movb????$24,????%dh?????#?右下角行??????movb????$79,????%dl?????#?右下角列??????movb????$0x07,??%bh?????#?空白區域屬性??????int?????$0x10??????ret????#---------------------------------------------------------------??#?直接寫顯存顯示一些文字函數:??#???調用前需要設置DS:SI為源地址,DI為顯示位置,??#???CX?為顯示的字符個數,?AL為顏色屬性??draw_some_text:??????#?ES:DI?is?the?dst?address,?DS:SI?is?the?src?address??????movw????$VIDEO_SEG_TEXT,????%bx??????movw????%bx,????????????????%es????????copy_a_char:??????movsb??????stosb??????loop????copy_a_char??????ret????#----------------------------------------------------------------??#?讀取軟盤第二個扇區:??#???使用BIOS?INT?0x13中斷,使用前需要設置ES:BX作為緩沖區??read_one_sect:??????movb????$0x02,??%ah?????#?功能號??????movb????$0x01,??%al?????#?讀取扇區數??????movb????$0x00,??%ch?????#?柱面號??????movb????$0x02,??%cl?????#?扇區號??????movb????$0x00,??%dh?????#?磁頭號??????movb????$0x00,??%dl?????#?驅動器號????re_read:????????????????????#?若調用失敗則重新調用??????int?????$0x13??????jc??????re_read?????????#?若進位位(CF)被置位,表示調用失敗????????????ret????main:??????movw????%cx,????%ax??????movw????%ax,????%ds??????movw????%ax,????%es????????call????clear_screen????????#?清屏????????movw????$0,?????????%ax??????movw????%ax,????????%ds??????leaw????msg_str,????%si??????xorw????%di,????????%di??????movw????msg_len,????%cx??????movb????$TEXT_COLOR,%al??????call????draw_some_text??????#?繪制字符串????????movw????$BUFFER_SEG,%ax???????????movw????%ax,????????%es?????#?ES:BX?為緩沖區地址??????xorw????%bx,????????%bx??????call????read_one_sect????????#?下面調用繪制函數,在屏幕上顯示讀取的信息??????movw????$BUFFER_SEG,%ax??????movw????%ax,????????%ds?????#?ds:si?為源地址??????xorw????%si,????????%si??????movw????$160,???????%di?????#?第一行已經打印了msg_str,從第二行開始顯示??????movw????$512,???????%cx?????#?顯示512個字符??????movb????$0x01,??????%al??????call????draw_some_text????1:??????jmp?????1b????msg_str:??????.asciz??"The?data?of?the?second?sect?of?the?floppy?(sect?1):"??msg_len:??????.int????.?-?msg_str?-?1????????.org????0x1fe,??0x90??????.word???0xaa55??
實驗結果:
6.讀取任意扇區(給定相對扇區號)
實驗,寫用C語言寫入文件,該文件包含512個‘a’,512個1……512個‘z’, 循環50次,將該文件寫入軟盤(相對扇區號1~50*26),然后讀取給定的相對扇區號的扇區,將讀取的內容打印到屏幕上。并與寫入的數據比較,驗證讀取的正確性。
[cpp] view plaincopyprint?
C代碼用于寫文件:???????????#include?<stdio.h>??#include?<string.h>????int?main(int?argc,?char?*argv[])??{??????if?(argc?!=?2)??????{??????????printf("usage:?./write_data?file_name");??????????exit(0);??????}????????FILE?*fp;??????fp?=?fopen(argv[1],?"wb");????????????int?i,?j,?k;????????for?(i?=?0;?i?<?50;?i++)??????{??????????for?(j?=?'a';?j?<=?'z';?j++)??????????{??????????????for?(k?=?0;?k?<?512;?k++)??????????????{??????????????????fprintf(fp,?"%c",?(char)j);??????????????}??????????}??????}????????return?0;??}????匯編代碼:??#?This?program?draws?color?pixels?at?mode?0x13??#?2012-12-26?20:23:42??#?guzhoudiaoke@126.com????.include?"boot.inc"????.section?.text??.global?_start??.code16????_start:??????jmp?????main????#--------------------------------------------------------------??#?清屏函數:??#???設置屏幕背景色,調色板的索引0指代的顏色為背景色??clear_screen:???????????????#?清屏函數??????movb????$0x06,??%ah?????#?功能號0x06??????movb????$0,?????%al?????#?上卷全部行,即清屏??????movb????$0,?????%ch?????#?左上角行??????movb????$0,?????%ch?????#?左上角列????????movb????$24,????%dh?????#?右下角行??????movb????$79,????%dl?????#?右下角列??????movb????$0x07,??%bh?????#?空白區域屬性??????int?????$0x10????????????ret????#---------------------------------------------------------------??#?直接寫顯存顯示一些文字函數:??#???調用前需要設置DS:SI為源地址,DI為在屏幕上的顯示位置,??#???CX?為顯示的字符個數,?AL為顏色屬性??draw_some_text:??????#?ES:DI?is?the?dst?address,?DS:SI?is?the?src?address??????movw????$VIDEO_SEG_TEXT,????%bx??????movw????%bx,????????????????%es????????copy_a_char:??????movsb??????stosb??????loop????copy_a_char????????ret????#----------------------------------------------------------------??#?讀取軟盤一個扇區:??#???使用BIOS?INT?0x13中斷,使用前需要設置ES:BX作為緩沖區??#???AX為相對扇區號??read_one_sect:??????movb????$36,????%dl??????divb????%dl??????movb????%al,????%ch?????#?柱面號=N?/?36,?假設x?=?N?%?36????????????movb????%ah,????%al?????#?AL?=?N?%?36??????movb????$0,?????%ah?????#?AX?=?N?%?36??????movb????$18,????%dl??????divb????%dl??????movb????%al,????%dh?????#?磁頭號DH?=?x?/?18??????movb????%ah,????%cl???????????incb????%cl?????????????#?扇區號CL?=?x?%?18?+?1????????movb????$0x00,??%dl?????#?驅動器號DL????????movb????$0x02,??%ah?????#?功能號??????movb????$0x01,??%al?????#?讀取扇區數????re_read:????????????????????#?若調用失敗則重新調用??????int?????$0x13??????jc??????re_read?????????#?若進位位(CF)被置位,表示調用失敗????????????ret????#-------------------------------------------------------------------??#?該函數讀取指定的若干扇區號??#???需要指定ES:BX作為緩沖區??read_sects:??????movw????$0x00,??????????%si?????#?已經讀取的扇區數??????leaw????sect_no,????????%di??1:????????movw????(%di),??????????%ax?????#?獲取相對扇區號??????addw????$2,?????????????%di????????????call????read_one_sect??????????????incw????%si??????incw????%bx??????cmpw????num_to_read,????%si??????jne?????1b????????ret????main:??????movw????%cx,????%ax??????movw????%ax,????%ds??????movw????%ax,????%es????????call????clear_screen????????#?清屏????????#?顯示提示信息??????movw????$0,?????????%ax??????movw????%ax,????????%ds??????leaw????msg_str,????%si??????xorw????%di,????????%di??????movw????msg_len,????%cx??????movb????$TEXT_COLOR,%al??????call????draw_some_text??????#?繪制字符串????????#?讀取軟盤??????movw????$BUFFER_SEG,????????%ax???????????movw????%ax,????????????????%es?????#?ES:BX?為緩沖區地址??????xorw????%bx,????????????????%bx??????call????read_sects????????#?在屏幕上顯示讀取的信息??#???movw????$BUFFER_SEG,%ax??#???movw????%ax,????????%ds?????#?ds:si?為源地址??#???movw????$0,?????????%si??#???movw????$320,???????%di?????#?第一行已經打印了msg_str,從第二行開始顯示??#???movw????$512,???????%cx?????#?顯示字符數??#???movb????$0x01,??????%al??#???call????draw_some_text????????????#?將緩沖區中前data_len個字節拷貝到data_save??????xorw????%ax,????????%ax??????movw????%ax,????????%ds??????movw????num_to_read,%cx????????????movw????$BUFFER_SEG,%ax??????movw????%ax,????????%ds??????xorw????%ax,????????%ax??????movw????%ax,????????%es??????movw????$0,?????????%si??????movw????$data_save,?%di????????cld??????rep?????movsb????????#?下面調用繪制函數,在屏幕上顯示讀取的信息??????xorw????%ax,????????%ax??????movw????%ax,????????%ds?????#?ds:si?為源地址??????leaw????data_save,??%si??????movw????$160,???????%di?????#?第一行已經打印了msg_str,從第二行開始顯示??????movw????num_to_read,%cx?????#?顯示字符數??????movb????$0x01,??????%al??????call????draw_some_text????1:??????jmp?????1b????msg_str:??????.asciz??"The?data?read?from?floppy:"??msg_len:??????.short??.?-?msg_str?-?1????sect_no:??????#?下面的扇區數據為:"babyosguzhoudiaoke"??????#?sect:?2+26*1,?????1+26*2,?????2+26*3,?????25+26*4,????15+26*5,????19+26*6,??????????#???????7+26*11,????21+26*12,???26+26*13,???8+26*14,????15+26*15,???21+26*16,??????#???????4+26*31,????9+26*32,????1+26*33,????15+26*34,???11+26*35,???5+26*36??????.short??28,?????????53,?????????80,?????????129,????????145,????????175???????.short??293,????????333,????????364,????????372,????????379,????????411??????.short??810,????????841,????????859,????????899,????????921,????????941??num_to_read:??????.short??18????data_save:??????.asciz??"XXXXXXXXXXXXXXXXXX"????????????.org????0x1fe,??0x90??????.word???0xaa55??
[cpp] view plaincopyprint?
<pre></pre>??<pre></pre>??????
總結
以上是生活随笔為你收集整理的babyos (三)——利用BIOS INT 0x13读取软盘的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。