对第二天代码进行了修改,只打印hello ,uos没一点意思。
读取磁盘上10个柱面的1-18个扇区,(目前ssd已经没有柱面这个概念了)。读出来的数据放入内存0x8200起始的地方。
启动区放在0x8000内存扇区中。为什么要放在0x8000以后的内存中的呢? 只是因为这块内存没有用而已。
为什么要将启动程序(img的0扇区)放在0x7c00处? 这是ibm规定的。
向一个空软盘保存文件时:
1.文件名会写在0x002600以后的地方。
2.文件内容会写在0x004200以后的地方。
所以若想启动位于0x004200的程序,就得让引导程序运行完成后跳转到0x8000+0x4200=0xc200处。
作者这一块写的很混乱啊,咱们整理一下为啥是0xc200地址,看下图:
bios会把磁盘0位置的内容拷贝到内存0x7c00这个位置然后跳过去执行, 也就是把A拷贝到了内存,然后执行A A会把磁盘后面的内容从内存0x8200开始拷贝 这样的话磁盘0x4200位置就会对应到内存0xC200 一个扇区512字节,十六进制表示就是0x200
程序的执行情况:
1.bios读取磁盘0扇区到0x7c00处。
2.bios跳转到0x7c00处开始执行,该处为ipl10.nas程序,该程序功能为加载磁盘[1-最后]扇区到内存的0x8200处。并跳转到0xc200处执行。
3.0xc200处为asmhead.nas程序,该程序功能为,调用显卡bios,设置画面模式,调用操作系统代码。
4.操作系统代码目前就一个功能就是让cpu睡眠,开始进入c程序。
下面根据功能修改代码:
ipl10.nas:
; haribote-ipl ; TAB=4 CYLS EQU 10 ; 声明CYLS=10 ORG 0x7c00 ; 指明程序装载地址 ; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy code JMP entry DB 0x90 DB "HARIBOTE" ; 启动扇区名称(8字节) DW 512 ; 每个扇区(sector)大小(必须512字节) DB 1 ; 簇(cluster)大小(必须为1个扇区) DW 1 ; FAT起始位置(一般为第一个扇区) DB 2 ; FAT个数(必须为2) DW 224 ; 根目录大小(一般为224项) DW 2880 ; 该磁盘大小(必须为2880扇区1440*1024/512) DB 0xf0 ; 磁盘类型(必须为0xf0) DW 9 ; FAT的长度(必??9扇区) DW 18 ; 一个磁道(track)有几个扇区(必须为18) DW 2 ; 磁头数(必??2) DD 0 ; 不使用分区,必须是0 DD 2880 ; 重写一次磁盘大小 DB 0,0,0x29 ; 意义不明(固定) DD 0xffffffff ; (可能是)卷标号码 DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格) DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格) RESB 18 ; 先空出18字节 ; 程序主体 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 readloop: MOV SI,0 ; 记录失败次数寄存器 retry: MOV AH,0x02 ; AH=0x02 : 读入磁盘 MOV AL,1 ; 1个扇区 MOV BX,0 MOV DL,0x00 ; A驱动器 INT 0x13 ; 调用磁盘BIOS JNC next ; 没出错则跳转到next ADD SI,1 ; 往SI加1 CMP SI,5 ; 比较SI与5 JAE error ; SI >= 5 跳转到error MOV AH,0x00 MOV DL,0x00 ; A驱动器 INT 0x13 ; 重置驱动器 JMP retry next: MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换) ADD AX,0x0020 MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行 ADD CL,1 ; 往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 ; 读取完毕,跳转到haribote.sys执行! MOV [0x0ff0],CH ; 记下IPL读到哪里了 JMP 0xc200 error: MOV SI,msg putloop: MOV AL,[SI] ADD SI,1 ; 给SI加1 CMP AL,0 JE fin MOV AH,0x0e ; 显示一个文字 MOV BX,15 ; 指定字符颜色 INT 0x10 ; 调用显卡BIOS JMP putloop fin: HLT ; 让CPU停止,等待指令 JMP fin ; 无限循环 msg: DB 0x0a, 0x0a ; 换行两次 DB "load error" DB 0x0a ; 换行 DB 0 RESB 0x7dfe-$ ; 填写0x00直到0x001fe DB 0x55, 0xaa我们在使用段寄存器时,以ES:BX这种方式表示地址,写成"MOV AL, [ES:BX]"她代表ES×16+BX内存地址。
这个操作系统实现了一个最简单的功能:让cpu睡眠
void io_hlt(void); void HariMain(void) { fin: io_hlt(); /* 执行naskfunc.nas里边的_io_hlt()函数。 */ goto fin; }加入这个文件是因为c程序不能调用HLT指令,所以使用c程序调用汇编程序,在汇编程序中用HLT让cpu睡眠。
; naskfunc ; TAB=4 [FORMAT "WCOFF"] ; 制作目标文件的模式 [BITS 32] ; 制作32位模式用的机器语言 ; 制作目标文件的信息。 [FILE "naskfunc.nas"] ; 源文件名信息 GLOBAL _io_hlt ; 程序中包含的函数名 ;实际的函数 [SECTION .text] ;目标中间中写了这些之后再写程序 _io_hlt: ; void io_hlt(void); 这个函数只执行了一个HLT命令,让cpu睡眠。 HLT RET本文代码下载地址:https://download.csdn.net/download/u011164819/12981508