图表控件 c++_用C/C++编写16位虚拟内核
文章的范圍是什么?
在本文中,我將試圖簡要介紹文件系統在引導加載程序中的重要性,并嘗試編寫一個虛擬內核,它只會顯示一個提示,讓用戶輸入文本。為什么我要嵌入我的引導加載程序到一個脂肪格式的軟盤,它是如何受益于我。因為有一篇文章太小,沒有提到文件系統,所以我會盡我最大的努力使它盡可能的簡短和簡單。
背景
- 如果您有任何語言的編程經驗,這篇文章對您確實有很大幫助。雖然這篇文章似乎相當入門,但在匯編和C中編寫程序對于引導來說可能是一項艱巨的任務。如果您是計算機編程新手,那么我建議您閱讀一些關于介紹編程和計算機基礎的教程,然后再回到本文。
- 在這篇文章中,我將以問答的方式向您介紹與計算機相關的各種術語。坦率地說,我會寫這篇文章,好像我是在向自己介紹這篇文章。為了確保我能理解它在我的日常生活中的重要性和目的,我們已經進行了許多問答式的對話。你所說的計算機是什么意思?或者為什么我需要它們,因為我比它們聰明得多?
此外,您還可以查看我以前的文章,以獲得關于引導加載程序的基本概念,以及如何在匯編和C中編寫一篇文章。
這是鏈接。
Http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part
Http://www.codeproject.com/Articles/668422/Writing-a-boot-loader-in-Assembly-and-C-Part
內容是如何組織的?
這是本文主題的細分部分。
- 引導加載程序限制
- 從引導程序調用磁盤上的其他文件
- FAT文件系統
- FAT工作流
- 發展環境
- 編寫一個胖的引導加載程序
- 發展環境
- 微型項目-編寫一個16位內核
- 測試內核
引導加載程序限制
在前幾篇文章中,我試圖編寫引導加載程序,在屏幕上打印彩色矩形之后,我想在其中嵌入更多的功能。但是,512字節的大小對我來說是一個很大的限制,我不能更新引導加載程序的代碼來做更多的事情.
挑戰如下
- 在引導加載程序中嵌入更多的功能代碼
- 將引導加載程序的大小限制為512字節。
我該如何處理上述問題?
讓我向你簡要介紹如下。
第一部分:
- 我將用C語言編寫一個名為kernel.c的程序,確保在其中正確地編寫了我想要的所有額外功能。
- 編譯可執行文件并將其保存為kernel.bin
- 現在,將kernel.bin文件復制到可引導驅動器到第二個扇區。
第二部分:
在引導加載程序中,我們所能做的就是將可引導驅動器的第二個扇區(kernel.bin)加載到地址(例如0x1000)的RAM內存中,然后從0x7c00跳轉到0x1000位置,開始執行kernel.bin文件。
從引導程序調用磁盤上的其他文件
早些時候,我們了解到,我們實際上可以將控件從引導加載程序(0x7c00)傳遞到內存中的磁盤文件(如kernel.bin)的其他位置,然后繼續進行。但我腦子里沒什么疑問。
您知道kernel.bin文件將占用多少扇區嗎?
我覺得這很簡單。我們所要做的就是
1扇區=512字節
因此,如果kernel.bin的大小是512字節,那么它將占用1個扇區,如果大小為1024字節,則占用2個扇區,以此類推。
現在,重點是基于kernel.bin文件的大小,您必須硬編碼引導加載程序中的kernel.bin文件要讀取的扇區數。
這意味著,如果您想要通過頻繁更新內核來升級內核,您還必須記住記錄內核.bin文件在引導加載程序中占據的扇區的數量,否則內核崩潰。
如果您想要在您的可引導驅動器中添加更多的文件,如office.bin、entertainment.bin、drivers.bin、kernel.bin,您會怎么想?
在某個時候,您要做的就是一個一個地將文件附加到軟盤中,在這個過程中,您必須繼續更新引導加載器,了解引導磁盤上每個文件的確切位置,以及每個文件正在消耗的扇區的數量,以及更多的扇區。
但我想提醒大家的一點是,慢慢地,系統變得越來越復雜,而且不知怎么的,我很喜歡它。
您如何知道您在引導扇區后面附加的文件是否是您想要的文件?
我們所做的就是從引導加載程序將各自的扇區加載到內存中,然后開始執行它。但這并不完美,缺少了一些東西。
少了什么?
我認為引導加載程序對每個文件一個一個地加載扇區,然后開始執行文件。但是即使在引導加載程序嘗試將文件加載到內存之前,也應該有一種方法來檢查這些文件是否存在于引導磁盤上。
如果我錯誤地將錯誤的文件復制到引導磁盤的第二扇區,然后更新引導加載程序,然后運行,會發生什么情況?
我的系統只是崩潰,用戶會丟棄我的系統,因為這不是他想要的。
因此,在這種情況下,我所需要的只是引導磁盤上的一個固定位置,其中所有的文件名都像書中的索引一樣被寫入。
我的引導加載程序將查詢軟盤的索引,查找文件的名稱,如果文件名列在索引中,則繼續將文件加載到內存中。
哇!這很好,我喜歡它,因為它節省了很多行動。
這消除了一些問題。
早期的引導加載程序過去盲目地加載其中硬編碼的扇區.
如果您不知道正在加載的文件是否正確,為什么要加載該文件?
解決辦法是什么?
我們所要做的就是組織上面列出的磁盤上的信息,然后開始組織數據,然后重新編寫引導加載程序,這樣它才能真正有效地加載文件。
這種大規模組織數據的方法稱為文件系統(FileSystem)。有許多類型的文件系統,有商業和免費的。下面我將列舉其中的幾個。
- 胖的
- FAT 16
- FAT 32
- NTFS
- 分機
- Ext 2
- EXT 3
- EXT 4
FAT文件系統
在我向您介紹文件系統之前,您需要了解的術語不多。
在FAT文件系統中,集群占用1個扇區,扇區在存儲介質上占512字節。因此,一個集群相當于一個FAT格式化磁盤驅動器上的一個扇區。
集群和扇區是FAT文件系統中最小的單元。
為了便于使用,FAT文件系統分為四個主要部分,它們如下所示。
- 啟動扇區
- 胖的
- 根目錄
- 數據區
為了更好的理解,我盡我最大的努力以圖片的形式展示給你。
現在讓我向你介紹每一部分。
引導扇區:
FAT格式化磁盤上的引導扇區嵌入一些與FAT相關的信息,因此每次將磁盤插入到系統中時,操作系統都會自動知道其文件系統。
操作系統讀取FAT格式化磁盤的引導扇區,然后解析所需的信息,然后識別文件系統的類型,然后開始相應地讀取內容。
嵌入在引導扇區內的FAT文件系統的信息稱為BootParameterBlock。
引導參數塊:
讓我向您展示引導參數塊中有關引導扇區的值。
文件分配表:
此表的作用類似于包含文件的下一個群集值的鏈接列表。
從FAT中為特定文件獲取的群集值有兩種有用的方法。
- 確定文件的結尾
- 如果集群值在0x0ff8和0x0fff之間,那么該文件在其他扇區中沒有數據(到達File的末尾)。
- 確定文件數據所在的下一個扇區
注:
我在圖片中提到了脂肪表1和2。你需要記住的是,一張桌子是另一張桌子的副本。如果來自某個表的數據丟失或損壞,則來自另一個表的數據可以充當備份。這純粹是為了引入兩個表而不是一個表。
根目錄:
根目錄的作用類似于磁盤上所有文件名列表的索引。因此,引導加載程序應該在根目錄中搜索文件名,如果它是正的,那么它可以在根目錄中找到第一個集群,然后相應地加載數據。
現在,在從根目錄中找到第一個集群之后,引導加載程序應該使用FAT表來查找下一個集群,以檢查文件的結尾。
數據區:
這是實際包含文件數據的區域。
一旦程序確定了文件的適當扇區,就可以從數據區域提取文件的數據。
FAT工作流
假設我們的引導加載程序應該將kernel.bin文件加載到內存中,然后執行它。現在,在這個場景中,我們所要做的就是將下面的功能編碼到我們的引導加載程序中。
將前11個字節的數據與根目錄表中從偏移量0開始的“kernel.bin”進行比較。
如果字符串匹配,則提取根目錄表中偏移量26處的“kernel.bin”文件的第一個集群。
現在有了“kernel.bin”文件的啟動集群。
您所要做的就是將集群轉換為相應的扇區,然后將數據加載到內存中。
現在,在找到“kernel.bin”文件的第一個扇區后,將其加載到內存中,然后在文件的下一個集群的文件分配表中查找,以檢查該文件是否仍然具有數據或文件結束。
下面是供您參考的圖表。
發展環境
要成功地完成這項任務,我們需要了解以下內容。有關它們的更多信息,請參閱我以前的文章。
- 操作系統(GNU Linux)
- 匯編程序(GNU匯編程序)
- 指令集(x86系列)
- 在x86微處理器的GNU匯編程序上編寫x86指令。
- 編譯器(C編程語言-GNU C編譯器GCC)
- 鏈接器(GNU鏈接器ld)
- 像Bochs這樣的x86仿真器用于我們的測試。
編寫一個胖的引導加載程序
下面是用于在FAT格式化磁盤上執行kernel.bin文件的代碼片段。
下面是引導程序
文件名:stage0.S
/********************************************************************************** ** ** Name : stage0.S ** Date : 23-Feb-2014 ** Version : 0.0.1 ** Source : assembly language ** Author : Ashakiran Bhatter ** ** Description: The main logic involves scanning for kernel.bin file on a ** fat12 formatted floppy disk and then pass the control to it ** for its execution ** Usage : Please read the readme.txt for more information ** ** **********************************************************************************/ .code16 .text .globl _start; _start:jmp _bootnop/*bios parameter block description of each entity *//*-------------------- -------------------------- */.byte 0x6b,0x69,0x72,0x55,0x58,0x30,0x2e,0x31 /* oem label */.byte 0x00,0x02 /* total bytes per sector */.byte 0x01 /* total sectors per cluster */.byte 0x01,0x00 /* total reserved sectors */.byte 0x02 /* total fat tables */.byte 0xe0,0x00 /* total directory entries */.byte 0x40,0x0b /* total sectors */.byte 0xf0 /* media description */.byte 0x09,0x00 /* size in of each fat table */.byte 0x02,0x01 /* total sectors per track */.byte 0x02,0x00 /* total heads per cylinder */.byte 0x00,0x00, 0x00, 0x00 /* total hidden sectors */.byte 0x00,0x00, 0x00, 0x00 /* total big sectors */.byte 0x00 /* boot drive identifier */.byte 0x00 /* total unused sectors */.byte 0x29 /* external boot signature */.byte 0x22,0x62,0x79,0x20 /* serial number */.byte 0x41,0x53,0x48,0x41,0x4b,0x49 /* volume label 6 bytes of 11 */.byte 0x52,0x41,0x4e,0x20,0x42 /* volume label 5 bytes of 11 */.byte 0x48,0x41,0x54,0x54,0x45,0x52,0x22 /* file system type *//* include macro functions */#include "macros.S"/* begining of main code */ _boot:/* initialize the environment */initEnvironment /* load stage2 */loadFile $fileStage2/* infinite loop */ _freeze:jmp _freeze/* abnormal termination of program */ _abort:writeString $msgAbortjmp _freeze/* include functions */#include "routines.S"/* user-defined variables */bootDrive : .byte 0x0000msgAbort : .asciz "* * * F A T A L E R R O R * * *"#fileStage2: .ascii "STAGE2 BIN"fileStage2: .ascii "KERNEL BIN"clusterID : .word 0x0000/* traverse 510 bytes from beginning */. = _start + 0x01fe/* append boot signature */.word BOOT_SIGNATURE這是主加載程序文件執行以下操作。
- 初始化所有寄存器并通過調用initEnvironment宏設置堆棧。
- 調用loadFile宏將kernel.bin文件加載到地址0x1000:0000的內存中,然后將控制傳遞給它以供進一步執行。
文件名:宏S
這是一個包含所有預定義宏和宏函數的文件。
/********************************************************************************* * ** ** Name : macros.S ** Date : 23-Feb-2014 ** Version : 0.0.1 ** Source : assembly language ** Author : Ashakiran Bhatter ** ** **********************************************************************************/ /* predefined macros: boot loader */ #define BOOT_LOADER_CODE_AREA_ADDRESS 0x7c00 #define BOOT_LOADER_CODE_AREA_ADDRESS_OFFSET 0x0000/* predefined macros: stack segment */ #define BOOT_LOADER_STACK_SEGMENT 0x7c00#define BOOT_LOADER_ROOT_OFFSET 0x0200 #define BOOT_LOADER_FAT_OFFSET 0x0200#define BOOT_LOADER_STAGE2_ADDRESS 0x1000 #define BOOT_LOADER_STAGE2_OFFSET 0x0000 /* predefined macros: floppy disk layout */ #define BOOT_DISK_SECTORS_PER_TRACK 0x0012 #define BOOT_DISK_HEADS_PER_CYLINDER 0x0002 #define BOOT_DISK_BYTES_PER_SECTOR 0x0200 #define BOOT_DISK_SECTORS_PER_CLUSTER 0x0001/* predefined macros: file system layout */ #define FAT12_FAT_POSITION 0x0001 #define FAT12_FAT_SIZE 0x0009 #define FAT12_ROOT_POSITION 0x0013 #define FAT12_ROOT_SIZE 0x000e #define FAT12_ROOT_ENTRIES 0x00e0 #define FAT12_END_OF_FILE 0x0ff8/* predefined macros: boot loader */ #define BOOT_SIGNATURE 0xaa55/* user-defined macro functions */ /* this macro is used to set the environment */ .macro initEnvironmentcall _initEnvironment .endm /* this macro is used to display a string */ /* onto the screen */ /* it calls the function _writeString to */ /* perform the operation */ /* parameter(s): input string */ .macro writeString messagepushw messagecall _writeString .endm /* this macro is used to read a sector into */ /* the target memory */ /* It calls the _readSector function with */ /* the following parameters */ /* parameter(s): sector Number */ /* address to load */ /* offset of the address */ /* Number of sectors to read */ .macro readSector sectorno, address, offset, totalsectorspushw sectornopushw addresspushw offsetpushw totalsectorscall _readSectoraddw $0x0008, %sp .endm /* this macro is used to find a file in the */ /* FAT formatted drive */ /* it calls readSector macro to perform this */ /* activity */ /* parameter(s): root directory position */ /* target address */ /* target offset */ /* root directory size */ .macro findFile file/* read fat table into memory */readSector $FAT12_ROOT_POSITION, $BOOT_LOADER_CODE_AREA_ADDRESS, $BOOT_LOADER_ROOT_OFFSET, $FAT12_ROOT_SIZEpushw filecall _findFileaddw $0x0002, %sp .endm /* this macro is used to convert the given */ /* cluster into a sector number */ /* it calls _clusterToLinearBlockAddress to */ /* perform this activity */ /* parameter(s): cluster number */ .macro clusterToLinearBlockAddress clusterpushw clustercall _clusterToLinearBlockAddressaddw $0x0002, %sp .endm /* this macro is used to load a target file */ /* into the memory */ /* It calls findFile and then loads the data */ /* of the respective file into the memory at */ /* address 0x1000:0x0000 */ /* parameter(s): target file name */ .macro loadFile file/* check for file existence */findFile filepushw %ax/* read fat table into memory */readSector $FAT12_FAT_POSITION, $BOOT_LOADER_CODE_AREA_ADDRESS, $BOOT_LOADER_FAT_OFFSET, $FAT12_FAT_SIZEpopw %axmovw $BOOT_LOADER_STAGE2_OFFSET, %bx _loadCluster:pushw %bxpushw %axclusterToLinearBlockAddress %axreadSector %ax, $BOOT_LOADER_STAGE2_ADDRESS, %bx, $BOOT_DISK_SECTORS_PER_CLUSTERpopw %axxorw %dx, %dxmovw $0x0003, %bxmulw %bxmovw $0x0002, %bxdivw %bxmovw $BOOT_LOADER_FAT_OFFSET, %bxaddw %ax, %bxmovw $BOOT_LOADER_CODE_AREA_ADDRESS, %axmovw %ax, %esmovw %es:(%bx), %axorw %dx, %dxjz _even_cluster _odd_cluster:shrw $0x0004, %axjmp _done _even_cluster:and $0x0fff, %ax _done:popw %bxaddw $BOOT_DISK_BYTES_PER_SECTOR, %bxcmpw $FAT12_END_OF_FILE, %axjl _loadCluster/* execute kernel */initKernel .endm /* parameter(s): target file name */ /* this macro is used to pass the control of */ /* execution to the loaded file in memory at */ /* address 0x1000:0x0000 */ /* parameters(s): none */ .macro initKernel/* initialize the kernel */movw $(BOOT_LOADER_STAGE2_ADDRESS), %axmovw $(BOOT_LOADER_STAGE2_OFFSET) , %bxmovw %ax, %esmovw %ax, %dsjmp $(BOOT_LOADER_STAGE2_ADDRESS), $(BOOT_LOADER_STAGE2_OFFSET) .endm環境:
- 此宏用于按需要設置段寄存器。
- 需要傳遞的參數數為零。
用途:環境
寫:
- 此宏用于將以空結尾的字符串顯示到屏幕上。
- 傳遞給它的參數是一個以空結尾的字符串變量。
用法:writeString<String變量>
讀者群:
- 此宏用于從磁盤讀取給定扇區,然后將其加載到目標地址。
- 需要傳遞的參數數為4個。
用途:讀取器<扇區編號>、<目標地址>、<目標地址偏移>、<總扇區讀取>
FindFile:
- 此宏用于檢查文件是否存在。
- 傳遞所需的參數數為1。
用法:findFile<目標文件名>
集群ToLinearBlockAddress:
- 此宏用于將給定的群集id轉換為扇區號。
- 傳遞所需的參數數為1。
用法:clusterToLinearBlockAddress<群集ID>
加載文件:
- 此宏用于將目標文件加載到內存中,然后將執行控件傳遞給它。
- 傳遞所需的參數數為1。
用法:loadFile<目標文件名>
InitKernel:
- 此宏用于將執行控制傳遞到RAM上的特定地址位置。
- 需要傳遞的參數數為零。
用法:initKernel
文件名:程序化
/********************************************************************************** ** ** Name : routines.S ** Date : 23-Feb-2014 ** Version : 0.0.1 ** Source : assembly language ** Author : Ashakiran Bhatter ** ** **********************************************************************************/ /* user-defined routines */ /* this function is used to set-up the */ /* registers and stack as required */ /* parameter(s): none */ _initEnvironment:pushw %bpmovw %sp, %bp _initEnvironmentIn:climovw %cs, %axmovw %ax, %dsmovw %ax, %esmovw %ax, %ssmovw $BOOT_LOADER_STACK_SEGMENT, %spsti _initEnvironmentOut:movw %bp, %sppopw %bp ret/* this function is used to display a string */ /* onto the screen */ /* parameter(s): input string */ _writeString:pushw %bpmovw %sp , %bpmovw 4(%bp) , %sijmp _writeStringCheckByte _writeStringIn:movb $0x000e, %ahmovb $0x0000, %bhint $0x0010incw %si _writeStringCheckByte:movb (%si) , %alorb %al , %aljnz _writeStringIn _writeStringOut:movw %bp , %sppopw %bp ret/* this function is used to read a sector */ /* into the target memory */ /* parameter(s): sector Number */ /* address to load */ /* offset of the address */ /* Number of sectors to read */ _readSector:pushw %bpmovw %sp , %bpmovw 10(%bp), %axmovw $BOOT_DISK_SECTORS_PER_TRACK, %bxxorw %dx , %dxdivw %bxincw %dxmovb %dl , %clmovw $BOOT_DISK_HEADS_PER_CYLINDER, %bxxorw %dx , %dxdivw %bxmovb %al , %chxchg %dl , %dhmovb $0x02 , %ahmovb 4(%bp) , %almovb bootDrive, %dlmovw 8(%bp) , %bxmovw %bx , %esmovw 6(%bp) , %bxint $0x13jc _abortcmpb 4(%bp) , %aljc _abortmovw %bp , %sppopw %bp ret/* this function is used to find a file in */ /* the FAT formatted drive */ /* parameter(s): root directory position */ /* target address */ /* target offset */ /* root directory size */ _findFile:pushw %bpmovw %sp , %bpmovw $BOOT_LOADER_CODE_AREA_ADDRESS, %axmovw %ax , %esmovw $BOOT_LOADER_ROOT_OFFSET, %bxmovw $FAT12_ROOT_ENTRIES, %dxjmp _findFileInitValues_findFileIn:movw $0x000b , %cxmovw 4(%bp) , %sileaw (%bx) , %direpe cmpsbje _findFileOut _findFileDecrementCount:decw %dxaddw $0x0020, %bx _findFileInitValues:cmpw $0x0000, %dxjne _findFileInje _abort _findFileOut:addw $0x001a , %bxmovw %es:(%bx), %axmovw %bp, %sppopw %bp ret/* this function is used to convert the given*/ /* cluster into a sector number */ /* parameter(s): cluster number */ _clusterToLinearBlockAddress:pushw %bpmovw %sp , %bpmovw 4(%bp) , %ax _clusterToLinearBlockAddressIn:subw $0x0002, %axmovw $BOOT_DISK_SECTORS_PER_CLUSTER, %cxmulw %cxaddw $FAT12_ROOT_POSITION, %axaddw $FAT12_ROOT_SIZE, %ax _clusterToLinearBlockAddressOut:movw %bp , %sppopw %bp ret
_環境:
- 此函數用于按需要設置段寄存器。
- 需要傳遞的參數數為零。
用法:Call_initEnvironment
_寫:
- 此函數用于將以空結尾的字符串顯示到屏幕上。
- 傳遞給它的參數是一個以空結尾的字符串變量。
用法:
- 推<字符串變量>
- 調用寫字符串
- 加$0x02,%sp
讀者群:
- 此宏用于從磁盤讀取給定扇區,然后將其加載到目標地址。
- 需要傳遞的參數數為4個。
用法:
- 推<扇形>
- 推<地址>
- 推送<偏移>
- 推動<總扇區>
- 呼叫讀取器
- 加$0x0008,%sp
FindFile:
- 此函數用于檢查文件是否存在。
- 傳遞所需的參數數為1。
用法:
- 推送<目標文件變量>
- 調用查找文件
- 加$0x02,%sp
集群ToLinearBlockAddress:
- 此宏用于將給定的群集id轉換為扇區號。
- 傳遞所需的參數數為1。
用法:
- 推<群集ID>
- 調用集群ToLinearBlockAddress
- 加$0x02,%sp
加載文件:
- 此宏用于將目標文件加載到內存中,然后將執行控件傳遞給它。
- 傳遞所需的參數數為1。
用法:
- 推送<目標文件>
- 調用加載文件
- 加$0x02,%sp
文件名:stage0.ld
此文件用于在鏈接時間內鏈接stage0.object文件。
文件名:bochsrc.txt
這是運行Bochs模擬器所需的配置文件,用于測試目的。
megs: 32 floppya: 1_44=../iso/stage0.img, status=inserted boot: a log: ../log/bochsout.txt mouse: enabled=0微型項目-編寫一個16位內核
下面的文件是作為測試過程的一部分引入的虛擬內核的源代碼。我們所要做的就是使用make文件編譯源代碼,并查看它是否由引導程序加載。
在文本中顯示帶有龍圖像的飛濺屏幕,然后顯示歡迎屏幕和命令提示符,以便用戶鍵入任何內容。
這里沒有寫好要執行的命令或實用程序,但只是為了測試目的,引入了這個內核,到目前為止,它還是一文不值的。
文件名:kernel.c/********************************************************************************* * * * * * Name : kernel.c * * Date : 23-Feb-2014 * * Version : 0.0.1 * * Source : C * * Author : Ashakiran Bhatter * * * * Description: This is the file that the stage0.bin loads and passes the * * control of execution to it. The main functionality of this * * program is to display a very simple splash screen and a * * command prompt so that the user can type commands * * Caution : It does not recognize any commands as they are not programmed * * * *********************************************************************************/ /* generate 16 bit code */ __asm__(".code16n"); /* jump to main function or program code */ __asm__("jmpl $0x1000, $mainn"); #define TRUE 0x01 #define FALSE 0x00 char str[] = "$> "; /* this function is used to set-up the */ /* registers and stack as required */ /* parameter(s): none */ void initEnvironment() { __asm__ __volatile__( "cli;" "movw $0x0000, %ax;" "movw %ax, %ss;" "movw $0xffff, %sp;" "cld;" ); __asm__ __volatile__( "movw $0x1000, %ax;" "movw %ax, %ds;" "movw %ax, %es;" "movw %ax, %fs;" "movw %ax, %gs;" ); } /* vga functions */ /* this function is used to set the */ /* the VGA mode to 80*24 */ void setResolution() { __asm__ __volatile__( "int $0x10" : : "a"(0x0003) ); } /* this function is used to clear the */ /* screen buffer by splitting spaces */ void clearScreen() { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0200), "b"(0x0000), "d"(0x0000) ); __asm__ __volatile__ ( "int $0x10" : : "a"(0x0920), "b"(0x0007), "c"(0x2000) ); } /* this function is used to set the */ /* cursor position at a given column */ /* and row */ void setCursor(short col, short row) { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0200), "d"((row <<= 8) | col) ); } /* this function is used enable and */ /* disable the cursor */ void showCursor(short choice) { if(choice == FALSE) { __asm__ __volatile__( "int $0x10" : : "a"(0x0100), "c"(0x3200) ); } else { __asm__ __volatile__( "int $0x10" : : "a"(0x0100), "c"(0x0007) ); } } /* this function is used to initialize*/ /* the VGA to 80 * 25 mode and then */ /* clear the screen and set the cursor*/ /* position to (0,0) */ void initVGA() { setResolution(); clearScreen(); setCursor(0, 0); } /* io functions */ /* this function is used to get a chara*/ /* cter from keyboard with no echo */ void getch() { __asm__ __volatile__ ( "xorw %ax, %axn" "int $0x16n" ); } /* this function is same as getch() */ /* but it returns the scan code and */ /* ascii value of the key hit on the */ /* keyboard */ short getchar() { short word; __asm__ __volatile__( "int $0x16" : : "a"(0x1000) ); __asm__ __volatile__( "movw %%ax, %0" : "=r"(word) ); return word; } /* this function is used to display the*/ /* key on the screen */ void putchar(short ch) { __asm__ __volatile__( "int $0x10" : : "a"(0x0e00 | (char)ch) ); } /* this function is used to print the */ /* null terminated string on the screen*/ void printString(const char* pStr) { while(*pStr) { __asm__ __volatile__ ( "int $0x10" : : "a"(0x0e00 | *pStr), "b"(0x0002) ); ++pStr; } } /* this function is used to sleep for */ /* a given number of seconds */ void delay(int seconds) { __asm__ __volatile__( "int $0x15" : : "a"(0x8600), "c"(0x000f * seconds), "d"(0x4240 * seconds) ); } /* string functions */ /* this function isused to calculate */ /* length of the string and then return*/ /* it */ int strlength(const char* pStr) { int i = 0; while(*pStr) { ++i; } return i; } /* UI functions */ /* this function is used to display the */ /* logo */ void splashScreen(const char* pStr) { showCursor(FALSE); clearScreen(); setCursor(0, 9); printString(pStr); delay(10); } /* shell */ /* this function is used to display a */ /* dummy command prompt onto the screen */ /* and it automatically scrolls down if */ /* the user hits return key */ void shell() { clearScreen(); showCursor(TRUE); while(TRUE) { printString(str); short byte; while((byte = getchar())) { if((byte >> 8) == 0x1c) { putchar(10); putchar(13); break; } else { putchar(byte); } } } } /* this is the main entry for the kernel*/ void main() { const char msgPicture[] = " .. nr" " ++` nr" " :ho. `.-/++/. nr" " `/hh+. ``:sds: nr" " `-odds/-` .MNd/` nr" " `.+ydmdyo/:--/yMMMMd/ nr" " `:+hMMMNNNMMMddNMMh:` nr" " `-:/+++/:-:ohmNMMMMMMMMMMMm+-+mMNd` nr" " `-+oo+osdMMMNMMMMMMMMMMMMMMMMMMNmNMMM/` nr" " ``` .+mMMMMMMMMMMMMMMMMMMMMMMMMMMMMNmho:.` nr" " `omMMMMMMMMMMMMMMMMMMNMdydMMdNMMMMMMMMdo+- nr" " .:oymMMMMMMMMMMMMMNdo/hMMd+ds-:h/-yMdydMNdNdNN+ nr" " -oosdMMMMMMMMMMMMMMd:` `yMM+.+h+.- /y `/m.:mmmN nr" " -:` dMMMMMMMMMMMMMd. `mMNo..+y/` . . -/.s nr" " ` -MMMMMMMMMMMMMM- -mMMmo-./s/.` ` nr" " `+MMMMMMMMMMMMMM- .smMy:.``-+oo+//:-.` nr" " .yNMMMMMMMMMMMMMMd. .+dmh+:. `-::/+:. nr" " y+-mMMMMMMMMMMMMMMm/` ./o+-` . nr" " :- :MMMMMMMMMMMMMMMMmy/.` nr" " ` `hMMMMMMMMMMMMMMMMMMNds/.` nr" " sNhNMMMMMMMMMMMMMMMMMMMMNh+. nr" " -d. :mMMMMMMMMMMMMMMMMMMMMMMNh:` nr" " /. .hMMMMMMMMMMMMMMMMMMMMMMMMh. nr" " . `sMMMMMMMMMMMMMMMMMMMMMMMMN. nr" " hMMMMMMMMMMMMMMMMMMMMMMMMy nr" " +MMMMMMMMMMMMMMMMMMMMMMMMh "; const char msgWelcome[] = " *******************************************************nr" " * *nr" " * Welcome to kirUX Operating System *nr" " * *nr" " *******************************************************nr" " * *nr" " * *nr" " * Author : Ashakiran Bhatter *nr" " * Version: 0.0.1 *nr" " * Date : 01-Mar-2014 *nr" " * *nr" " ******************************************************"; initEnvironment(); initVGA(); splashScreen(msgPicture); splashScreen(msgWelcome); shell(); while(1); }
讓我簡單介紹一下這些職能:
環境():
- 這是一個函數,用于設置段寄存器,然后設置堆棧.
- 所需參數為零。
- 用途:initEnvironment();
SET決議():
- 此函數用于將視頻模式設置為80*25。
- 所需參數為零。
- 用法:set決議();
ClearScreen():
- 此函數用于用空格填充屏幕緩沖區。
- 所需參數數為零。
- 用途:ClearScreen();
SetCursor():
- 此函數用于設置屏幕上給定位置的光標位置。
- 所需參數數為2。
- 用法:setCursor(列、行);
秀柯莎():
- 此函數用于根據用戶的選擇啟用或禁用游標。
- 所需參數數為1。
- 用法:顯示電流(1);
InitVGA():
- 此函數用于將視頻分辨率設置為80*25,然后清除屏幕,最后將光標設置為(0,0)在屏幕上。
- 所需參數數為零。
- 用法:initVGA();
Getch():
- 此函數用于從沒有回顯的用戶處獲得擊鍵。
- 所需參數數為零。
- 用法:Getch();
Getchar():
- 此函數用于返回鍵掃描代碼和相應的ascii代碼。
- 所需參數為零。
- 用法:putchar();
Putchar():
- 此函數用于在屏幕上顯示字符。
- 所需參數數為1。
- 用法:putchar(字符);
PrintString():
- 此函數用于返回鍵掃描代碼和相應的ascii代碼。
- 所需參數為零。
- 用法:getchar();
延遲():
- 此函數用于顯示以空結尾的字符串。
- 所需參數數為1。
- 用法:printString(空終止字符串變量);
鏈長():
- 此函數用于返回以空結尾的字符串的長度。
- 所需參數數為1。
- 用法:字符串長度(空終止字符串變量);
SplashScreen():
- 這個函數被用來在屏幕上顯示一些花哨的圖像一段時間。
- 所需參數數為1。
- 用法:SplashScreen(空終止字符串變量);
外殼():
- 此函數用于在屏幕上顯示提示符。
- 所需參數為零。
- 用法:shell();
下面是引導加載程序加載的內核的屏幕截圖。
測試內核
使用“源代碼”:
附加的是文件源ecode.tar.gz,它包含所需的源文件以及生成二進制文件所需的目錄。
因此,請確保您是系統的超級用戶,然后開始將文件解壓縮到目錄或文件夾中。
請確保安裝了Bochs-x64模擬器和GNU bin-utils,以便進一步編譯和測試源代碼。
下面是從zip中提取文件后將看到的目錄結構。
應該有5個目錄
- 箱子
- 國際標準化組織
- 核
- 原木
- SRC
一旦環境就緒,請確保打開一個終端,然后運行以下命令
- CD$(目錄)/src
- Mak-f制造試驗
- 博克斯
總結
以上是生活随笔為你收集整理的图表控件 c++_用C/C++编写16位虚拟内核的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python开发信息系统权限设置_[Py
- 下一篇: excel模糊匹配两列文字_Excel快