图表控件 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文件。
/********************************************************************************** ** ** Name : stage0.ld ** Date : 23-Feb-2014 ** Version : 0.0.1 ** Source : assembly language ** Author : Ashakiran Bhatter ** ** **********************************************************************************/
SECTIONS
{. = 0x7c00;.text :{_ftext = .;} = 0
}
文件名: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位虚拟内核相关推荐
- java绘制图表控件_画图控件 Chart Control -Java架构师必看
.NET3.5中中推出了图表控件,可以同时支持Web和WinForm两种方式,由于平时很少使用,一直网络 .NET3.5中中推出了图表控件,可以同时支持Web和WinForm两种方式,由于平时很少使用 ...
- 道路测量xy坐标表示什么_.NET图表控件LightningChart.NET案例研究:智能测量解决方案...
LightningChart.NET原名LightningChart Ultimate SDK. LightningChart.NET完全由GPU加速,并且性能经过优化,可用于实时显示海量数据-超过1 ...
- delphi 图表 控件_将基本图表集成到Delphi应用程序中
delphi 图表 控件 In most modern database applications some kind of graphical data representation is pref ...
- 构建仪表、图表控件的绘制框架
开发环境: VS2003 + Windows XP SP2测试环境: Windows XP SP2Demo截图 编写图形相关的控件需要完成两部分:1 绘制:2 与窗口类(泛指)集成使之成为控件.本文重 ...
- 微软图表控件MsChart
转自:http://tech.ddvip.com/2008-11/122640479791375.html 昨天在网上看到了微软发布了.NET 3.5框架下的图表控件,第一时间抓下来看了一下,发觉功能 ...
- 跨平台图表控件TeeChart使用教程:导入XML数据
2019独角兽企业重金招聘Python工程师标准>>> TeeChart的最新版中包含了一个自动加载XML数据的新组件.这个组件的名字叫做TTeeXMLSource,用户可以在Tee ...
- 漂亮好用的ASP.NET图表控件 免费的
绝对免费,绝对好用,中文支持绝对好,轻松生成漂亮的2D和3D图表. 这个控件是我找到的免费图表控件中非常好的一个,我一直在关注这个控件,虽然功能未必比得上商业的图表控件强大,但是绝对好用,绝对免费,他 ...
- labview波形图两个游标,LabVIEW数据可视化:使用波形图表控件逐点显示曲线的方法...
LabVIEW平台中提供了强大的2D/3D数据的可视化控件,如波形图.波形图表.XY图.强度图.数字波形图.混合信号图.二维/三维图片及用于特殊用途的极坐标图.Smith图.雷达图控件等. 上篇文章: ...
- 微软图表控件MsChart使用说明[转]
微软图表控件MsChart使用说明 建立一个.NET3.5的Web项目,像使用普通控件一样拖放到要使用的Web界面即可.初步研究了一下,整个图形控件主要由以下几个部份组成: 1.Annotations ...
最新文章
- mysql40190_MySQL 内核深度优化
- GNU ARM汇编--(二)汇编编译链接与运行
- 抽象类和接口有什么区别?
- 计算机动漫设计VR主要学什么,动漫设计专业学什么 要学什么软件
- 百度API_获取当前详细地址
- 一些奇妙的线段树操作
- https://zeplin.io/ 设计图标注及切图
- LeetCode(884)——两句话中的不常见单词(JavaScript)
- 买基金的一个很重要的知识
- disruptor小结--生产者代码
- 蜘蛛侠天堂,打死我mac键盘
- 485转61850规约转换C语言,61850规约转换器
- 目标检测之FPN网络详解
- 计算机如何输入极限符号,如何录入文本与符号 输入极限公式:Word符号与公式录入宝典第八篇...
- python求方程的根_python计算方程式根的方法
- Excel中如果对合并单元格求和
- 机器学习算法基础之使用python代码
- 茗香茶艺网/茶叶宣传网站
- Linux下Nginx+Resin负载均衡,session问题解决实例
- 【开发工具】SVN断网续传、续下解决办法
热门文章
- 多个硬件体验如一,华为终端分布式技术会重构IoT生态吗?
- 乐橙本地录像回放不了_本地工具访问:安全、高效、合规的IT资源远程访问
- 服务器手工修改虚拟内存,服务器修改虚拟内存
- mysql 嵌入式 c开发环境_【Linux】嵌入式C语言MySQL编程(libmysqlclient-dev使用)
- vue抽屉_VUE组件中的 Drawer 抽屉实现代码
- Java爬虫技术(一)普通网站爬取图片
- 解决w: pt/sources.list:18 中被配置了多次
- idea没有out文件夹_史上最详细没有之一的 Java JNI傻瓜级入门教程
- 结构体命名中的尾标ST是什么意思?(struct)
- int main中char** argv与char *argv[]区别?(main函数)