龙空技术网

第03天,32位模式+导入C语言《30天自制操作系统学习笔记》

数据重构生活 244

前言:

目前你们对“flacs软件教学视频”都比较关心,我们都想要分析一些“flacs软件教学视频”的相关文章。那么小编在网上汇集了一些有关“flacs软件教学视频””的相关资讯,希望同学们能喜欢,大家快快来了解一下吧!

前天制作了第一个扇区(512字节)的内容了,俗称启动区。

今天要制作第二个扇区(512字节)的内容,俗称启动程序装载区IPL(Initial Program Loader)。

制作IPL程序装载区

更新:ipl.nas文件

在entry中增加内容

entry:    MOV                AX,0                            MOV                SS,AX    MOV                SP,0x7c00    MOV                DS,AX  ;读磁盘    MOV                AX,0x0820    MOV                ES,AX    MOV                CH,0                       ; 柱面 = 0    MOV                DH,0                       ; 磁头 = 0    MOV                CL,2                        ; 扇区 = 2    MOV                AH,0x02                  ; AH=0x02 : 读盘    MOV                AL,1                        ; 扇区 = 1个    MOV                BX,0    MOV                DL,0x00                   ; A驱动器    INT                   0x13                        ; 调用磁盘BIOS    JC                     errorerror:                MOV                SI,msg

1张软盘有80个柱面,2个磁头,18个扇区(每个扇区有 512字节)。

1张软盘的容量是: 80×2×18×512 = 1 474 560 Byte = 1 440KB。

启动区:位于C0-H0-S1(CH柱面0,DH磁头0,CL扇区1的缩写)。

IPL程序装载区:位于C0-H0-S2(CH柱面0,DH磁头0,CL扇区2的缩写)。

又出现了新单词(功能)

CH

DH

CL

CH柱面

DH磁头

CL扇区

AH

AL

DL

AH=0x02;(读盘)

AH=0x03;(写盘)

AH=0x04;(校验)

AH=0x0c;(寻道)

AL=处理对象的扇区数;(只能同时处理连续的扇区)

DL=驱动器号;

JC

jump if carry

如果进位标志(carry flag)

AH==1就跳转FLACS.CF==0:没有错误.

AH==0就跳转FLAGS.CF==1:有错误,

错误号码存入AH内(与重置 (reset)功能一样)

更详细的细枝末节,大家看看书

咱们探讨漂浮在水面上的内容(水深!)

BUG无处不在

不论是软件还是硬件,bug无处不在!

读取软盘数据时会遇到读取异常,所以新增了一个功能:重试5次!!!

更新:ipl.nas文件

entry:    MOV                AX,0                            MOV                SS,AX    MOV                SP,0x7c00    MOV                DS,AX ;读磁盘    MOV                AX,0x0820    MOV                ES,AX    MOV                CH,0                        ; 柱面 = 0    MOV                DH,0                        ; 磁头 = 0    MOV                CL,2                        ; 扇区 = 2    MOV                SI,0                        ; 记录失败次数retry:    MOV                AH,0x02                  ; AH=0x02 : 读盘    MOV                AL,1                        ; 扇区 = 1个    MOV                BX,0    MOV                DL,0x00                   ; A驱动器    INT                0x13                          ; 调用磁盘BIOS        JNC                fin                                 ADD                SI,1                         ;每次增加1,相当于x++    CMP                SI,5                         ;判断语句,如果SI>=5    JAE                  error                       ;如果SI>=5时,跳转到error        MOV                AH,0x00    MOV                DL,0x00                  ; A驱动器    INT                   0x13                        ; 重置驱动器(系统复位)    JMP                  retryerror:                MOV                SI,msg

JNC

Jump if not carry 条件跳转指令 ,进位标志位0就跳转

JAE

Jump if above or equal 条件跳转指令,大于等于时跳转

第二个扇区弄好了!

设置18个扇区

话说,1张软盘有80个柱面,2个磁头,18个扇区。

既然弄完了前2个扇区,剩下的16个扇区也弄弄吧!

更新:ipl.nas文件

【记录失败次数】做成独立功能readloop增加next功能,自动填写剩余扇区

readloop:            MOV                SI,0                        	 ; 记录失败次数next:    MOV                AX,ES                       ; 内存地址后移0x200        ADD                AX,0x0020								; 因为没有ADD ES,0x020指令,需要变通    MOV                ES,AX                                ADD                CL,1                        ; CL=CL+1    CMP                CL,18                       ; 比较CL=?18    JBE                readloop               		 ; 如果CL <= 18 跳转到readloop

JBE

“jump if below or equal 跳转指令,小于等于

要读下一个扇区,只需给CL(扇区号)加1

已经把磁盘上C0-H0-S2到C0-H0- S18的512×17=8 704字节的内容,

装载到了内存的0x8200~0xa3ff处。

18个扇区弄好了

设置10个柱面

话说,1张软盘有80个柱面,2个磁头,18个扇区。

C0-H0-S18扇区的下一扇区,是磁盘反面的C0-H1-S1直到C0-H1-S18。

然后又跑到反面从C1-H0-S1开始读取扇面,直到C9-H1- S18

更新:ipl.nas内容,并把文件名改为ipl10.nas

提醒大家这个程序只能读入10个柱面

next:		;---------这是读取18个扇区的方法    MOV                AX,ES                        ; 内存地址后移0x200    ADD                AX,0x0020    MOV                ES,AX                        ; 因为没有ADD ES,0x020指令,需要变通    ADD                CL,1                        ; CL=CL+1    CMP                CL,18                        ; 比较CL=?18    JBE                readloop                ; 如果CL <= 18 跳转到readloop        ;-----------这是磁盘正反面跳转的方法    MOV                CL,1    ADD                DH,1    CMP                DH,2    JB                readloop                ; 如果DH < 2 跳转到readloop        MOV                DH,0    ADD                CH,1    CMP                CH,CYLS    JB                readloop                ; 如果CH < CYLS 跳转到readloop

JB

jump if below 如果小于,就跳转

EQU

equal 相当于C语言的#define命令,

用来声明常数 “CYLS EQU 10”意思是“CYLS = 10” (CYLS代 表cylinders)

10个柱面就用几行代码设置好了!

正事干完了,划划水。

更新:Makefile文件

把重复的内容写到顶部,做成公共设施

使用变量时,套上$和( )

TOOLPATH = ../z_tools/MAKE     = $(TOOLPATH)make.exe -rNASK     = $(TOOLPATH)nask.exeEDIMG    = $(TOOLPATH)edimg.exeIMGTOL   = $(TOOLPATH)imgtol.comCOPY     = copyDEL      = del# 默认default :        $(MAKE) img# 生成文件规则ipl.bin : ipl.nas Makefile        $(NASK) ipl.nas ipl.bin ipl.lstharibote.img : ipl.bin Makefile        $(EDIMG)   imgin:../z_tools/fdimg0at.tek \                wbinimg src:ipl.bin len:512 from:0 to:0   imgout:haribote.img# 命令asm :        $(MAKE) ipl.binimg :        $(MAKE) haribote.imgrun :        $(MAKE) img        $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin        $(MAKE) -C ../z_tools/qemuclean :        -$(DEL) ipl.bin        -$(DEL) ipl.lstsrc_only :        $(MAKE) clean        -$(DEL) haribote.img

一顿操作猛如虎,好像又没干什么

如果懒?不改!

开发操作系统

今天是第三天,把虚拟机复制到day3文件夹内

来看看harib00e文件夹

多了haribote.nas文件

真会起名,haribote = 哈利波特

看看内容,只有3行代码

fin:    HLT    JMP fin

这是休眠功能,用来省电,毕竟1度电=0.5毛,节约是传统美德!

我们要用haribote.nas生成haribote.sys 和haribote.lst

然后,用ipl.bin 和haribote.sys生成haribote.img

看到img文件了

makefile新增内容

haribote.sys : haribote.nas Makefile        $(NASK) haribote.nas haribote.sys haribote.lstharibote.img : ipl.bin haribote.sys Makefile        $(EDIMG)   imgin:../z_tools/fdimg0at.tek \                wbinimg src:ipl.bin len:512 from:0 to:0 \                copy from:haribote.sys to:@: \                imgout:haribote.img

测试:打开cmd.bat,输入make img

(文件夹harib00e)

第一次见到sys文件,好奇心又上来了

用BZ打开haribote.sys文件看看

文件名称,写在0x00:2600地址以后的地方;文件内容,写在0x00:4200地址以后的地方。

之前我们规划了启动区和装载区

启动区执行的是haribote.sys内容

从启动区执行操作系统

虽然知道程序内容在磁盘映像上0x00:4200地址,但是怎么执行呢?

首先要明白,磁盘内容最终要装载到内存地址。

而对于磁盘来说,在内存中的第一个地址不是0x00:0000,而是0x00:8000。

所以我们要做一下加法运算0x00:8000+0x00:4200=0x00:c200

所以启动区内容位于内存的0x00:c200地址,缩写成0xc200

把内存地址写到nas内部

更新:haribote.nas

; haribote-os; TAB=4                ORG                0xc200                        fin:                HLT                JMP                fin

跳转到内存地址

更新:ipl.nas

next:    ....此处省略一大堆代码,自行脑补,脑补不成看源文件    ;增加内容    JMP     0xc200

测试:打开cmd,输入make run

连个hello world都没有,看不出是否成功执行操作系统!

确认操作系统的执行情况

之前是黑屏白字

这次弄个图形界面

更新:haribote.nas

; haribote-os; TAB=4                ORG                0xc200                        ; 程序内容的内存地址                MOV                AL,0x13                        ; VGA显卡,320x200 x8bit色彩                MOV                AH,0x00                INT                   0x10fin:                HLT                JMP                fin

图形模式只用了三行代码!

AL,0x03:16色字符模式,80 × 25 AL,0x12:VGA 图形模式,640 × 480 × 4位彩色模式,独特的4面 存储模式 AL,0x13:VGA 图形模式,320 × 200 × 8位彩色模式,调色板模式 ( 用256种颜色 )AL,0x6a:扩展VGA 图形模式,800 × 600 × 4位彩色模式,独特的 4面存储模式(有的显卡不支持)设定AH=0x00后,调用显卡BIOS的函数,这样就可以切换显示模式了

更新:ipl.nas文件

next:   .....内容自行脑补    ;增加内容    MOV                [0x0ff0],CH                 ; 赋值,磁盘装载内容的开始地址(内存地址)0x0ff0    JMP                  0xc200												;跳到,磁盘装载内容的开始地址(内存地址)0xc200

我们知道了磁盘装载内容的开始地址(内存)是0xc200,还需要知道结束地址(内存)0x0ff0,这样启动区程序算完成。

总结一下

img 文件:用来给磁盘分区(启动区和装载区)sys 文件:操作系统内容(被启动区识别)其他文件:生成这两个文件的过渡文件

测试:打开cmd,输入make run

如果懒的写代码,运行harib00g文件夹

wuhoo~~~

成功调用图形界面!

虽然只有嘿嘿嘿

32位模式预热准备

16位优势:直接调用BIOS函数(因为BIOS是用16位机器语言写的)。

32位优势:使用更多的寄存器,但不能直接调用BIOS函数,需要变通一下。

64位优势:难度大,先放弃

看看32位中如何使用BIOS函数

修改:haribote.nas文件

; haribote-os; TAB=4; --------------------有关BOOT_INFO   (information信息)CYLS         EQU                0x0ff0                        ; 设定启动区LEDS         EQU                0x0ff1                        ;LED灯泡VMODE     EQU                0x0ff2                        ; 关于颜色数目的信息,颜色的位数SCRNX       EQU                0x0ff4                        ; 分辨率的X(screen x)SCRNY        EQU                0x0ff6                        ; 分辨率的Y(screen y)VRAM        EQU                0x0ff8                        ; 图像缓冲区的开始地址;----------------------------------内容装载开始地址                ORG                0xc200                        ; 内容开始地址;----------------------------------切换显卡                MOV                AL,0x13                        ; VGA显卡。320x200x8bit位色彩                MOV                AH,0x00                INT                   0x10;----------------------------------设置画面以及分辨率                MOV                BYTE [VMODE],8                        ; 记录画面模式                MOV                WORD [SCRNX],320                  ;分辨率宽320像素                MOV                WORD [SCRNY],200                   ;分辨率高200像素                MOV                DWORD [VRAM],0xa0000          ;显卡内存,即video RAM; ------------------------------------用BIOS取得键盘上各种LED指示灯状态                MOV                AH,0x02                INT                    0x16                         ; keyboard BIOS                MOV                [LEDS],AL;--------------------------------------休眠功能,省电!fin:                HLT                JMP                fin

导入C语言

一开始学机器语言

后来又学了汇编语言

现在又学C语言

我们要把haribote.sys改名为asmhead.nas

新增了很多内容,大家不要怕!作者说了,为了用C语言,不得不写进去,以后会看懂!

; haribote-os; TAB=4BOTPAK        EQU                0x00280000                DSKCAC        EQU                0x00100000                DSKCAC0        EQU                0x00008000                    ; 有关BOOT_INFO   (information信息)CYLS        EQU                0x0ff0                        ; 设定启动区LEDS        EQU                0x0ff1VMODE        EQU                0x0ff2                        ; 关于颜色数目的信息,颜色的位数SCRNX        EQU                0x0ff4                        ; 分辨率的X(screen x)SCRNY        EQU                0x0ff6                        ; 分辨率的Y(screen y)VRAM        EQU                0x0ff8                        ; 图像缓冲区的开始地址                ORG                0xc200                        ; 这个程序将被装在到内存指定位置                MOV                AL,0x13                        ; VGA显卡。320x200x8bit位色彩                MOV                AH,0x00                INT                0x10                MOV                BYTE [VMODE],8        ; 记录画面模式                MOV                WORD [SCRNX],320                MOV                WORD [SCRNY],200                MOV                DWORD [VRAM],0x000a0000; 用BIOS取得键盘上各种LED指示灯状态                MOV                AH,0x02                INT                0x16                         ; keyboard BIOS                MOV                [LEDS],AL; ----------------------------以下是新增内容,为了写C语言                MOV                AL,0xff                OUT                0x21,AL                NOP                                                                OUT                0xa1,AL                CLI                                                                CALL        waitkbdout                MOV                AL,0xd1                OUT                0x64,AL                CALL        waitkbdout                MOV                AL,0xdf                                        OUT                0x60,AL                CALL        waitkbdout[INSTRSET "i486p"]                                                LGDT        [GDTR0]                                        MOV                EAX,CR0                AND                EAX,0x7fffffff                        OR                EAX,0x00000001                        MOV                CR0,EAX                JMP                pipelineflushpipelineflush:                MOV                AX,1*8                                        MOV                DS,AX                MOV                ES,AX                MOV                FS,AX                MOV                GS,AX                MOV                SS,AX                MOV                ESI,bootpack                        MOV                EDI,BOTPAK                                MOV                ECX,512*1024/4                CALL        memcpy                MOV                ESI,0x7c00                                MOV                EDI,DSKCAC                                MOV                ECX,512/4                CALL        memcpy                MOV                ESI,DSKCAC0+512                        MOV                EDI,DSKCAC+512                        MOV                ECX,0                MOV                CL,BYTE [CYLS]                IMUL        ECX,512*18*2/4                        SUB                ECX,512/4                                CALL        memcpy                MOV                EBX,BOTPAK                MOV                ECX,[EBX+16]                ADD                ECX,3                                        SHR                ECX,2                                        JZ                skip                                        MOV                ESI,[EBX+20]                        ADD                ESI,EBX                MOV                EDI,[EBX+12]                        CALL        memcpyskip:                MOV                ESP,[EBX+12]                        JMP                DWORD 2*8:0x0000001bwaitkbdout:                IN                 AL,0x64                AND                 AL,0x02                JNZ                waitkbdout                                RETmemcpy:                MOV                EAX,[ESI]                ADD                ESI,4                MOV                [EDI],EAX                ADD                EDI,4                SUB                ECX,1                JNZ                memcpy                                        RET                ALIGNB        16GDT0:                RESB        8                                                DW                0xffff,0x0000,0x9200,0x00cf                        DW                0xffff,0x0000,0x9a28,0x0047                        DW                0GDTR0:                DW                8*3-1                DD                GDT0                ALIGNB        16bootpack:

下面开始就是C语言了

新建:bootpack.c文件,并添加内容(老规矩,创建txt文件,改后缀)

void HariMain(void){       fin:        goto fin;  }
函数(功能,技能)名字叫HariMain,且不带参数(void),不返回任何值程序就是从以HariMain命名的函数开始运行的,所以这个函数名不能更改goto实际上也是被编译成JMP指令

bootpack.c是怎样变成机器语言的呢?

使用cc1.exe从bootpack.c生成bootpack.gas。使用gas2nask.exe从bootpack.gas生成bootpack.nas。使用nask.exe从bootpack.nas生成bootpack.obj。使用obi2bim.exe从bootpack.obj生成bootpack.bim。使用bim2hrb.exe从bootpack.bim生成bootpack.hrb。使用copy指令将asmhead.bin与 bootpack.hrb单纯结合到起来,就成了haribote.sys。

接下来,把上面的生成命令写到makefile文件

修改:makefile文件

TOOLPATH = ../z_tools/INCPATH  = ../z_tools/haribote/MAKE     = $(TOOLPATH)make.exe -rNASK     = $(TOOLPATH)nask.exeCC1      = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quietGAS2NASK = $(TOOLPATH)gas2nask.exe -aOBJ2BIM  = $(TOOLPATH)obj2bim.exeBIM2HRB  = $(TOOLPATH)bim2hrb.exeRULEFILE = $(TOOLPATH)haribote/haribote.rulEDIMG    = $(TOOLPATH)edimg.exeIMGTOL   = $(TOOLPATH)imgtol.comCOPY     = copyDEL      = deldefault :        $(MAKE) imgipl10.bin : ipl10.nas Makefile        $(NASK) ipl10.nas ipl10.bin ipl10.lstasmhead.bin : asmhead.nas Makefile        $(NASK) asmhead.nas asmhead.bin asmhead.lstbootpack.gas : bootpack.c Makefile        $(CC1) -o bootpack.gas bootpack.cbootpack.nas : bootpack.gas Makefile        $(GAS2NASK) bootpack.gas bootpack.nasbootpack.obj : bootpack.nas Makefile        $(NASK) bootpack.nas bootpack.obj bootpack.lstnaskfunc.obj : naskfunc.nas Makefile        $(NASK) naskfunc.nas naskfunc.obj naskfunc.lstbootpack.bim : bootpack.obj naskfunc.obj Makefile        $(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \                bootpack.obj naskfunc.objbootpack.hrb : bootpack.bim Makefile        $(BIM2HRB) bootpack.bim bootpack.hrb 0haribote.sys : asmhead.bin bootpack.hrb Makefile        copy /B asmhead.bin+bootpack.hrb haribote.sysharibote.img : ipl10.bin haribote.sys Makefile        $(EDIMG)   imgin:../z_tools/fdimg0at.tek \                wbinimg src:ipl10.bin len:512 from:0 to:0 \                copy from:haribote.sys to:@: \                imgout:haribote.img                img :        $(MAKE) haribote.imgrun :        $(MAKE) img        $(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin        $(MAKE) -C ../z_tools/qemuinstall :        $(MAKE) img        $(IMGTOL) w a: haribote.imgclean :        -$(DEL) *.bin        -$(DEL) *.lst        -$(DEL) *.gas        -$(DEL) *.obj        -$(DEL) bootpack.nas        -$(DEL) bootpack.map        -$(DEL) bootpack.bim        -$(DEL) bootpack.hrb        -$(DEL) haribote.syssrc_only :        $(MAKE) clean        -$(DEL) haribote.img

这样大功告成了!

重新捋一遍文件作用(学多了,容易忘掉)

ipl10.nas:用来分区磁盘(启动区和装载区)asmhead.nas:设置bios函数等,为C语言调用提前设置bootpack.c:用来生成haribote.syscmd.bat:启用cmd窗口makefile:包含各种生成文件命令(核心文件img和sys)make.bat:一键生成所有文件,cmd都不用打开

实现HLT

最后再添加一个省电功能

新建:naskfunc.nas文件,添加以下内容(老规矩,创建txt,改后缀)

; naskfunc; TAB=4    [FORMAT "WCOFF"]              ; 制作目标文件的模式[BITS 32]                                ; 制作32位模式用的机械语言;制作目标文件的信息[FILE "naskfunc.nas"]         ; 源文件名信息    GLOBAL _io_hlt               ; 程序中包含的函数名    ;以下是实际的函数[SECTION .text]                   ; 目标文件中写了这些之后再写程序_io_hlt: ; void io_hlt(void);    HLT    RET

看不懂没关系,知道干啥用就可以

我们要在c语言中添加省电功能

修改:bootpack.c

void io_hlt(void);               /*告诉C编译器,有一个函数在别的文件里*/            void HariMain(void){  fin:      io_hlt();                         /*执行naskfunc.nas里的_io_hlt*/      goto fin;}

测试:打开cmd.bat,输入make run

(运行最后一个文件夹harib00j)

今天就到这里,洗洗睡了!

标签: #flacs软件教学视频 #fin c语言