读书笔记《30天自制操作系统》day03

来源:互联网 发布:林徽因 知乎 编辑:程序博客网 时间:2024/05/08 21:13

0. 自己试着在win7下用NASM和minGW改写汇编和C混合编程,结果受挫了。还是先使用作者提供的工具构建吧。

1. 通过前2天的工作已经能使用NASM制作一个映像了,并且编写的汇编代码可以成为引导扇区代码。

2. 引导扇区代码中可以调用BIOS中断,读取软盘上其它扇区到内存中,根据FAT12文件系统格式得知,保存到软盘内的第一个文件的文件名一定从19逻辑扇区开始,且该文件的内容从逻辑扇区33开始(见day01,图一)。

3. 引导扇区可以将第一个保存的文件(asmhead.nas,功能是跳入保护模式并调用C语言编写的函数代码)读入内存并使之执行,找这个文件用到了一个技巧(如2描述),不然通过文件系统结构分析出文件位置,并加载码就太复杂了。

4. 引导扇区代码如下ipl10.asm

CYLSEQU10ORG0x7c00JMPentryDB0x90DB"HARIBOTE"DW512DB1DW1DB2DW224DW2880DB0xf0DW9DW18DW2DD0DD2880DB0,0,0x29DD0xffffffffDB"HARIBOTEOS "DB"FAT12   "RESB18entry:MOVAX,0MOVSS,AXMOVSP,0x7c00MOVDS,AXMOVAX,0x0820  ;目的地址MOVES,AXMOVCH,0   ;柱面号MOVDH,0   ;磁头号MOVCL,2   ;扇区号readloop:MOVSI,0retry:MOVAH,0x02   ;读磁盘MOVAL,1   ;读1个扇区MOVBX,0       ;目的地址MOVDL,0x00   ;驱动器号INT0x13   ;来BIOS中断JNCnextADDSI,1CMPSI,5JAEerror   ;读五次还失败就放弃MOVAH,0x00    ;重置驱动器功能号MOVDL,0x00   ;驱动器号INT0x13JMPretrynext:MOVAX,ESADDAX,0x0020   ;保存位置向后移动512字节,0x0020是段地址加偏移量后成为0x0200了MOVES,AXADDCL,1CMPCL,18       ;读18个扇区JBEreadloopMOVCL,1ADDDH,1CMPDH,2JBreadloopMOVDH,0ADDCH,1CMPCH,CYLSJBreadloopMOV[0x0ff0],CHJMP0xc200        ;跳到软盘kernel.sys(asmhead.nas+bootpack.c)文件内部执行                                              ;该文件在加载软盘文件基址0x8000+Fat12文件系统中文件出现位置0x004200处=0xc200Herror:                MOV             SI,msgputloop:                MOVAL,[SI]                ADDSI,1                CMPAL,0                JEfin                MOVAH,0x0e                MOVBX,15                INT0x10                JMPputloopfin:                HLT                JMPfinmsg:                DB0x0a, 0x0a                DB"load error"                DB0x0a                DB0;                RESB        0x7dfe-$                times           510-($-$$) db 0                DB0x55, 0xaa

BIOS 13中断说明(功能有磁盘的读、写、扇区校验、寻道)
AH=0x02 读盘/0x03写盘/0x04校验/0x0c寻道
AL=处理连续扇区数
CH=柱面号&0xff
CL=扇区号(0~5位)|(柱面号&0x300)>>2
DH=磁头号
DL=驱动器号
ES:BX=缓冲地址
返回值:FLAGS=0没有错误AH=0,FLAGS=1有错误AH保存错误码

 

5. 跳入保护模式代码如下asmhead.nas(1)准备GDT(2)用LGDT加载gdtr(3)打开A20(4)设置CR0的PE位(5)跳转进入保护模式

BOTPAKEQU0x00280000DSKCACEQU0x00100000DSKCAC0EQU0x00008000CYLSEQU0x0ff0LEDSEQU0x0ff1VMODEEQU0x0ff2SCRNXEQU0x0ff4SCRNYEQU0x0ff6VRAMEQU0x0ff8ORG0xc200 ;让引导扇区加载后从这里开始运行,认为它们在一个段中所以能直接跳转过来MOVAL,0x13;保存信息MOVAH,0x00INT0x10MOVBYTE [VMODE],8MOVWORD [SCRNX],320MOVWORD [SCRNY],200MOVDWORD [VRAM],0x000a0000MOVAH,0x02INT0x16 ; keyboard BIOSMOV[LEDS],ALMOVAL,0xff                 ;禁止PIC主从片的中断      OUT0x21,ALNOP;不能有两个连续的OUT指令OUT0xa1,ALCLI                        ;禁止PIC工作要在CLI之前CALLwaitkbdout                      ;等待键盘电路准备好,要设置A20使1MB以上内存能被访问MOVAL,0xd1OUT0x64,ALCALLwaitkbdoutMOVAL,0xdf; enable A20OUT0x60,ALCALLwaitkbdout[INSTRSET "i486p"]LGDT[GDTR0]        ;加载临时的GDT表首地址到GDTR寄存器MOVEAX,CR0ANDEAX,0x7fffffffOREAX,0x00000001MOVCR0,EAX                 ;设置CR0寄存器PE标志位JMPpipelineflush           ;设置标志位之后马上JMPpipelineflush:                                          ;从此寻址方式变了MOVAX,1*8                  ;段值的设置,用GDT中那个段(GDT+1段)MOVDS,AXMOVES,AXMOVFS,AXMOVGS,AXMOVSS,AXMOVESI,bootpack        ;将bootpack.c生成的目标代码移动到0x00280000,乾坤大挪移MOVEDI,BOTPAKMOVECX,512*1024/4CALLmemcpyMOVESI,0x7c00              ;将启动扇区复制到1MB以后的内存MOVEDI,DSKCACMOVECX,512/4CALLmemcpyMOVESI,DSKCAC0+512        ;将0x00008200数据复制到0x00100200MOVEDI,DSKCAC+512MOVECX,0MOVCL,BYTE [CYLS]IMUL        ECX,512*18*2/4SUBECX,512/4CALLmemcpy                ;至此内存中0x00100000部分与磁盘内容就一样了                   ;调用bootpack.c的初始化操作,解析bootpack.hrb的header并传入参数MOVEBX,BOTPAKMOVECX,[EBX+16]ADDECX,3SHRECX,2JZskipMOVESI,[EBX+20]ADDESI,EBXMOVEDI,[EBX+12]CALLmemcpyskip:MOVESP,[EBX+12]JMPDWORD 2*8:0x0000001b          ;跳到指定段中跳过可执行文件头p421waitkbdout:IN AL,0x64AND AL,0x02JNZwaitkbdoutRETmemcpy:MOVEAX,[ESI]ADDESI,4MOV[EDI],EAXADDEDI,4SUBECX,1JNZmemcpyRETALIGNB16GDT0:                                                            ;临时设计的GDT表RESB8DW0xffff,0x0000,0x9200,0x00cfDW0xffff,0x0000,0x9a28,0x0047DW0GDTR0:                                                           ;临时设计的GDT选择子DW8*3-1DDGDT0ALIGNB16bootpack:

6. C语言代码如下bootpack.c

void io_hlt(void);void write_mem8(int addr,int data);void HariMain(void){int i;for(i=0xa0000;i<=0xaffff;i++){write_mem8(i,15);        /*向内存的0xa0000~0xaffff位置写入信息,这块内存是显存空间,15是白色*/ }for(;;){io_hlt();}}


7. C语言中调用的io_hlt和write_mem8函数放到了如下代码中func.asm

[FORMAT "WCOFF"][INSTRSET "i486p"][BITS 32][FILE "naskfunc.nas"]global _io_hlt,_write_mem8[section .text];void io_hlt(void);_io_hlt:HLTRET;void write_mem8(int addr,int data);_write_mem8:MOV ECX,[ESP+4]MOV AL,[ESP+8]MOV [ECX],ALRET

8. 在toolset文件夹内建立一个新文件夹,将上面所有的文件放在里边,编译链接接上面的文件,写个bat文件如下

nasm -o ipl10.bin ipl10.asm  ;生成引导扇区代码nasm -o img.img img.asm      ;生成软盘镜像文件..\z_tools\nask.exe asmhead.nas asmhead.bin..\z_tools\cc1.exe -I..\z_tools\haribote\ -Os -Wall -quiet -o bootpack.gas bootpack.c..\z_tools\gas2nask.exe -a bootpack.gas bootpack.nas..\z_tools\nask.exe bootpack.nas bootpack.obj..\z_tools\nask.exe func.asm func.obj..\z_tools\obj2bim.exe @..\z_tools\haribote\haribote.rul out:bootpack.bim stack:3136k map:bootpack.map bootpack.obj func.obj..\z_tools\bim2hrb.exe bootpack.bim bootpack.hrb 0copy /B asmhead.bin+bootpack.hrb kernel.sys


9.这样除了中间文件外,生成img.img文件和kernel.sys文件。使用winImage打开img.img文件将kernel.sys文件加入到该img文件中。

10. 启动Bochs,呵呵看见屏幕白了,这可是从C代码里控制的啊!

11. asmhead中跳入保护模式的代码慢慢在深入掌握,不然会掉入细节里不能自拔了。

12. (这句很经典)asmhead和C代码是通过copy /B进行链接的其中asmhead代码最后留了个标号bootpack,在这个标号后面C的目标代码被砍去文件头直接将代码链接到了这里,所以能实现从汇编跳转到C语言的目的。

原创粉丝点击