进入32位模式并导入c语言教程,《30天自制操作系统》读书笔记(3) 引入C语言

这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧.

作者提供的源码的注释在中文系统下是乱码, 而且代码的分隔用了两个Tab, 在这里要处理一下:

:%s/;.*//g 删除所有的注释;

:%s// 把两个Tab替换为一个Tab;

要让作者的nas文件和asm文件拥有相同的语法规则, 在_vimrc文件的最后一行添加

au BufNewFile,BufRead *.nas set filetype=asm

真正的IPL

之前我们写的只是软盘启动区代码, 所有代码只能放在512字节里, 根本不够用,

所以我们要利用这一段代码读入软盘的其他内容, 并将控制权移交给它, 所以叫做IPL(Initial Program Loader).

需要的知识点:

int 0x13 磁盘中断

AH = 0x02    ; 读盘

AH = 0x03    ; 写盘

AH = 0x04    ; 校验

AH = 0x0c    ; 寻道

AH = 0x00    ;大概是重置磁盘, 配合DH = 0x00 使用

AL = 连续处理的扇区数

CH = 柱面号

CL = 扇区号

DH = 磁头号

DL = 驱动器号

ES:BX = 缓冲地址, 寻道及校验不使用

C = 0 没有错误, AH = 0;

C = 1 错误号码存入AH.

这里只会用到0x02和0x00.

软盘的结构:

用柱面(C)-磁头(H)-扇区(S) 来标识软盘上的扇区, 我们的启动扇区的标号是C0-H0-S1, 值得注意的是下一个扇区是C0-H0-S2, 这个例子里作者要读入10个柱面, 从C0-H0-S1 读到 C9-H1-S18, 这样算来应该是18*2*10 = 360 个扇区, 大小是360*512/1024 = 180 KB, 从我们现在小的可怜的需求看来, 180KB绝对够了.(按这样算的话不是一个柱面有36个扇区吗? 此处不解).

afe93f36481f77abfdfc389b16a21e13.png

以下的代码能将软盘除启动区外开始的180KB的空间读入内存中, 起始地址是0x8200, 占用的空间是0x2d000.

执行软盘中的内容

编写Haribote.nas文件如下, 结构很简单:

1 fin:

2 HLT

3 JMP fin

问题是如何把编译好的程序和IPL结合在一起?

我们可以先编译好IPL, 和之前一样做成一个img, 然后把程序写入img.

最直观的方法是把img文件写入U盘, 把程序写入U盘, 再把U盘打包成img,

虽然有些迂回, 但是我们可以借助WinHex来直接写入, 用WinHex直接打开作者做好的Haribote.img ,可以发现它的内部格式如下:

fb0104f0d11271f222c03e6537560b32.png

发现Haribote.SYS处在0x4200的位置处 , 这是不是真的Haribote.sys?

7df41e93e4bbe641b3d8bda8cd11e5f9.png

也从Winhex里面打开Hraibote.sys:

1598b2d0205d99ae2360902b17578e8f.png

只有一句, F4 EB FD, 和img文件0x4200处的完全一样, 和作者的总结一样:

向一个空软盘保存文件的时候,

1.文件名会写在0x2600以后的地方(这里我没有去验证);

2.文件的内容会写入到0x4200以后的地方.

非空软盘的情况没有考虑(这里开始我们就真正意义上使用了FAT12的文件系统了, 而不是自己设计一个文件系统).

知道了这个我们就可以知道怎么调用这个程序了, 使用作者提供的edimg.exe 可以方便地将程序写入到img中, 所以Makefile也要做相应的改动, 具体看Project文件夹day3里面的e文件夹.

这个Haribote.nas 所做的只是不断HLT, 我们并不知道这段代码是否真的执行, 作者这里使用了0x10来切换画面模式, 使得光标消失,

参数是AL = 0x13, AH = 0x00, 效果是屏幕全黑, 连光标也不能看到.

我这里采用的是0x10中断的另一个功能, 能够显示带颜色的字符串, 代码如下:

1 ;Program

2 ORG 0xc200 ;加载到 0x8200 + 0x4200 – 0x200(启动区没有被读入)

3 MOV AX,0

4 MOVES,AX5 MOVAX,loaded6 MOV BP,AX ;ES:BP = 串地址

7 MOV CX,10 ;串长度

8 MOV AX,0x1301 ;AH = 0x13,AL = 0x01

9 MOV BX,0x000b ;页号BH = 0 黑底蓝字 BL = 0x0b

10 MOV DL,0

11 INT0x1012 JMPfin13 loaded:

14 DB 0x0a, 0x0a15 DB "Loaded."

16 DB 0x0a17 DB 0

18

19 fin:

20 HLT

21 JMP fin

效果如下, 可以确定我们Haribote.sys里面的代码已经被执行.

73b6773fc0108a550a2da8426fe3a21f.png

进入32位模式&导入C语言*

这里作者开始用我们看不懂的东西了, 给出了一个长长的asmhead.nas, 并且表示"先跳过这一部分", 让我有点不爽, 但是毕竟不能半途而废不是? 这里的Makefile变得越来越复杂, 在这里我第一次碰到了困难, 由于粗心Makefile写少了几行, 导致编译莫名其妙地出错, 纠结了两天才发现, 抄代码都能抄错 = =, 废话略过, 作者还增加了一个Bootpack.c 大概就是我们以后的主战场了, 这里编译过程异常繁琐(作者啊你可不可以不要用你自己写的工具!? (╯‵□′)╯︵┻━┻),

e23753ba31e8d50c54e59af681672f89.png

以上所有的工具都是川和先生写的或者改写的(╯‵□′)╯︵┻━┻.

需要强调的是HariMain这个Main函数的函数名已经写死了, 不能够更换, 为了在C

语言里面使用HLT, (事实上现在C语言里面根本就没有函数可用), 增加naskfunc.nas.

所有文件均如下:

IPL.nas:

;hello-os

;TAB=4

;const

CYLS EQU10ORG 0x7c00JMPentry

DB 0x90

DB"OS 0.01"DW512DB1DW1DB2DW224DW2880DB 0xf0

DW9DW18DW2DD0DD2880DB0,0,0x29

DD 0xffffffff

DB"OS ver 0.01"DB"FAT12"RESB18

entry:

MOV AX,0

MOVSS,AXMOVSP,0x7c00MOVDS,AXMOV AX,0x0820 ;缓存位置 = ES:BX

MOVES,AXMOV CH,0 ;柱面0

MOV DH,0 ;磁头0

MOV CL,2 ;扇区2

readloop:

MOV SI,0 ;记录失败次数

retry:

MOV AH,0x02 ;读盘

MOV AL,1 ;一个扇区

MOV BX,0

MOV DL,0x00 ;驱动器A:

INT 0x13 ;调用磁盘中断

JNCnextADD SI,1

CMP SI,5 ;失败5次跳出

JAEerrorMOVAH,0x00MOV DL,0x00 ;指定驱动器A:

INT 0x13 ;重置并重试

JMPretrynext:

MOVAX,ESADDAX,0x0020MOV ES,AX ;段寄存器往后移0x0020 实际偏移 0x0020*0x0010 = 0x0200 = 512d

ADD CL,1

CMP CL,18 ;读到18扇区

JBE readloop;<= 则跳

MOV CL,1

ADD DH,1 ;换一个磁头

CMP DH,2

JB readloop;

MOV DH,0

ADD CH,1 ;柱面+1

CMPCH,CYLSJBreadloopMOV[0x0ff0],CHJMP0xc200error: ;错误提示

MOV AX,0

MOVES,AXMOVAX,msgMOV BP,AX ;ES:BP = 串地址

MOV CX,14 ;串长度

MOV AX,0x1301 ;AH = 0x13,AL = 0x01

MOV BX,0x000c ;页号BH = 0 黑底红字 BL = 0x0c

MOV DL,0

INT0x10fin:

HLT

JMPfinmsg:DB 0x0a, 0x0a

DB"Load error."DB 0x0a

DB0RESB 0x7dfe-$

DB 0x55, 0xaa

Asmhead.nas:

BOTPAK EQU 0x00280000

DSKCAC EQU 0x00100000

DSKCAC0 EQU 0x00008000

CYLS EQU 0x0ff0;设定启动区LEDS EQU 0x0ff1

VMODE EQU 0x0ff2;关于颜色数目的信息,颜色的位数SCRNX EQU 0x0ff4;分辨率 X(Screen X)SCRNY EQU 0x0ff6;分辨率 Y(Screen Y)VRAM EQU 0x0ff8;图像缓冲区的起始地址ORG 0xc200MOV AL,0x13 ;VGA 显卡

MOVAH,0x00INT0x10MOV BYTE [VMODE],8 ;记录画面模式

MOV WORD [SCRNX],320

MOV WORD [SCRNY],200

MOVDWORD [VRAM],0x000a0000;取得键盘上的LED灯的状态

MOVAH,0x02INT0x16MOV[LEDS],ALMOVAL,0xffOUT0x21,ALNOP

OUT0xa1,ALCLI

CALLwaitkbdoutMOVAL,0xd1OUT0x64,ALCALLwaitkbdoutMOVAL,0xdfOUT0x60,ALCALLwaitkbdout

[INSTRSET"i486p"]LGDT[GDTR0]MOVEAX,CR0ANDEAX,0x7fffffffOREAX,0x00000001MOVCR0,EAXJMPpipelineflushpipelineflush:

MOV AX,1*8

MOVDS,AXMOVES,AXMOVFS,AXMOVGS,AXMOVSS,AXMOVESI,bootpackMOVEDI,BOTPAKMOV ECX,512*1024/4

CALLmemcpyMOVESI,0x7c00MOVEDI,DSKCACMOV ECX,512/4

CALLmemcpyMOV ESI,DSKCAC0+512

MOV EDI,DSKCAC+512

MOV ECX,0

MOVCL,BYTE [CYLS]IMUL ECX,512*18*2/4

SUB ECX,512/4

CALLmemcpyMOVEBX,BOTPAKMOV ECX,[EBX+16]ADD ECX,3

SHR ECX,2

JZskipMOV ESI,[EBX+20]ADDESI,EBXMOV EDI,[EBX+12]CALLmemcpyskip:

MOV ESP,[EBX+12]JMP DWORD 2*8:0x0000001bwaitkbdout:

INAL,0x64ANDAL,0x02JNZwaitkbdoutRET

memcpy:

MOVEAX,[ESI]ADD ESI,4

MOV[EDI],EAXADD EDI,4

SUB ECX,1

JNZmemcpyRETALIGNB16

GDT0:RESB8DW 0xffff,0x0000,0x9200,0x00cf

DW 0xffff,0x0000,0x9a28,0x0047

DW0

GDTR0:DW8*3-1DD GDT0

ALIGNB16

bootpack.c:

void io_hlt(void);void HariMain(void)

{

fin:

io_hlt();gotofin;

}

Naskkfunc.nas:

;naskfunc[FORMAT"WCOFF"] ;制作目标文件的模式[BITS32] ;制作32位模式用的机械语言

;制作目标文件的信息

[FILE"naskfunc.nas"] ;源文件名信息GLOBAL _io_hlt;程序中包含的函数名

;实际的函数[SECTION .text];

_io_hlt:

HLT

RETvoid io_hlt(void);void HariMain(void)

{fin:io_hlt();goto fin;}

万恶的Makefile:

TOOLPATH = ../z_tools/INCPATH= ../z_tools/haribote/MAKE= $(TOOLPATH)make.exe -r

NASK= $(TOOLPATH)nask.exe

CC1= $(TOOLPATH)cc1.exe -I$(INCPATH)-Os -Wall -quiet

GAS2NASK= $(TOOLPATH)gas2nask.exe -a

OBJ2BIM= $(TOOLPATH)obj2bim.exe

BIM2HRB= $(TOOLPATH)bim2hrb.exe

RULEFILE= $(TOOLPATH)haribote/haribote.rul

EDIMG= $(TOOLPATH)edimg.exeDEL = delSHORTCUT= "D:Program FilesOracleVirtualBoxVirtualBox.exe" --comment "OS1" --startvm "a5c4b0e6-e142-4720-98ee-056911204b29"default :$(MAKE)install$(MAKE) run

$(MAKE)clean

ipl10.bin : ipl10.nas Makefile$(NASK) ipl10.nas ipl10.bin ipl10.lst

asmhead.bin : asmhead.nas Makefile$(NASK) asmhead.nas asmhead.bin asmhead.lst

bootpack.gas : bootpack.c Makefile$(CC1) -o bootpack.gas bootpack.c

bootpack.nas : bootpack.gas Makefile$(GAS2NASK) bootpack.gas bootpack.nas

bootpack.obj : bootpack.nas Makefile$(NASK) bootpack.nas bootpack.obj bootpack.lst

naskfunc.obj : naskfunc.nas Makefile$(NASK) naskfunc.nas naskfunc.obj naskfucn.lst

bootpack.bim : bootpack.obj naskfunc.obj Makefile$(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map bootpack.obj naskfunc.objechoerror# 3MB+64KB=3136KB

bootpack.hrb : bootpack.bim Makefile$(BIM2HRB) bootpack.bim bootpack.hrb 0haribote.sys :asmhead.bin bootpack.hrb Makefilecopy /B asmhead.bin+bootpack.hrb haribote.sys

haribote.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

install:$(MAKE) haribote.imgrun:echo Running...

$(SHORTCUT)

echoFinished

clean :

-$(DEL) *.bin

-$(DEL) *.lst

-$(DEL) *.gas

-$(DEL) *.obj

-$(DEL) bootpack.nas

-$(DEL) bootpack.map

-$(DEL) bootpack.bim

-$(DEL) bootpack.hrb

-$(DEL) haribote.sys

-$(DEL) *.*~

-$(DEL)*~echo Finished.

这次更新慢了, 下次争取早一点…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值