本文主要是介绍30天自制操作系统:第三天,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
对第二天代码进行了修改,只打印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程序。
下面根据功能修改代码:
1.修改ipl.nas
ipl10.nas:
; haribote-ipl
; TAB=4CYLS EQU 10 ; 声明CYLS=10ORG 0x7c00 ; 指明程序装载地址; 标准FAT12格式软盘专用的代码 Stand FAT12 format floppy codeJMP entryDB 0x90DB "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 ; 不使用分区,必须是0DD 2880 ; 重写一次磁盘大小DB 0,0,0x29 ; 意义不明(固定)DD 0xffffffff ; (可能是)卷标号码DB "HARIBOTEOS " ; 磁盘的名称(必须为11字?,不足填空格)DB "FAT12 " ; 磁盘格式名称(必??8字?,不足填空格)RESB 18 ; 先空出18字节; 程序主体entry:MOV AX,0 ; 初始化寄存器MOV SS,AXMOV SP,0x7c00MOV DS,AX; 读取磁盘MOV AX,0x0820MOV ES,AXMOV CH,0 ; 柱面0MOV DH,0 ; 磁头0MOV CL,2 ; 扇区2readloop:MOV SI,0 ; 记录失败次数寄存器retry:MOV AH,0x02 ; AH=0x02 : 读入磁盘MOV AL,1 ; 1个扇区MOV BX,0MOV DL,0x00 ; A驱动器INT 0x13 ; 调用磁盘BIOSJNC next ; 没出错则跳转到nextADD SI,1 ; 往SI加1CMP SI,5 ; 比较SI与5JAE error ; SI >= 5 跳转到errorMOV AH,0x00MOV DL,0x00 ; A驱动器INT 0x13 ; 重置驱动器JMP retry
next:MOV AX,ES ; 把内存地址后移0x200(512/16十六进制转换)ADD AX,0x0020MOV ES,AX ; ADD ES,0x020因为没有ADD ES,只能通过AX进行ADD CL,1 ; 往CL里面加1CMP CL,18 ; 比较CL与18JBE readloop ; CL <= 18 跳转到readloopMOV CL,1ADD DH,1CMP DH,2JB readloop ; DH < 2 跳转到readloopMOV DH,0ADD CH,1CMP CH,CYLSJB readloop ; CH < CYLS 跳转到readloop; 读取完毕,跳转到haribote.sys执行!MOV [0x0ff0],CH ; 记下IPL读到哪里了JMP 0xc200error:MOV SI,msgputloop:MOV AL,[SI]ADD SI,1 ; 给SI加1CMP AL,0JE finMOV AH,0x0e ; 显示一个文字MOV BX,15 ; 指定字符颜色INT 0x10 ; 调用显卡BIOSJMP putloopfin:HLT ; 让CPU停止,等待指令JMP fin ; 无限循环msg:DB 0x0a, 0x0a ; 换行两次DB "load error"DB 0x0a ; 换行DB 0RESB 0x7dfe-$ ; 填写0x00直到0x001feDB 0x55, 0xaa
我们在使用段寄存器时,以ES:BX这种方式表示地址,写成"MOV AL, [ES:BX]"她代表ES×16+BX内存地址。
2.修改asmhead.nas
; haribote-os boot asm
; TAB=4;一些定义
BOTPAK EQU 0x00280000 ; bootpack�̃��[�h��
DSKCAC EQU 0x00100000 ; �f�B�X�N�L���b�V���̏ꏊ
DSKCAC0 EQU 0x00008000 ; �f�B�X�N�L���b�V���̏ꏊ�i���A�����[�h�j; 有关BOOT_INFO
CYLS EQU 0x0ff0 ; 设定启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 该位置保存颜色数目的信息,颜色的位数。
SCRNX EQU 0x0ff4 ; 该位置保存 分辨率的x
SCRNY EQU 0x0ff6 ; 该位置保存 分辨率的y
VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址。ORG 0xc200 ; 这个程序需要装载到内存的什么地方呢。; 画面设定MOV AL,0x13 ; VGA显卡,320*320*8位彩色,调色板模式。MOV AH,0x00INT 0x10 ;调用显卡bios的函数,切换显示模式。MOV BYTE [VMODE],8 ; 将画面模式信息保存到这些内存地址中。MOV WORD [SCRNX],320MOV WORD [SCRNY],200MOV DWORD [VRAM],0x000a0000
;VRAM指的时显卡内存,也就是用来显示画面的内存。这一块内存地址都对应着画面上的像素。
;VRAM在0xa0000~0xaffff之间的64kb。 VRAM分布在内存分布图中的好几个不同的地方。; 用bios取得键盘上各种led灯的状态。MOV AH,0x02INT 0x16 ; keyboard BIOSMOV [LEDS],AL;=====================================后边的留以后再看,这块时调用bootpack.c程序的======================
; 防止PIC接受所有中断
; AT兼容机的规范、PIC初始化
; 然后之前在CLI不做任何事就挂起
; PIC在同意后初始化MOV AL,0xffOUT 0x21,ALNOP ; ; 不断执行OUT指令OUT 0xa1,ALCLI ;进一步中断CPU; ; 让CPU支持1M以上内存、设置A20GATECALL waitkbdoutMOV AL,0xd1OUT 0x64,ALCALL waitkbdoutMOV AL,0xdf ; enable A20OUT 0x60,ALCALL waitkbdout; 保护模式转换[INSTRSET "i486p"] ; 说明使用486指令LGDT [GDTR0] ;设置临时GDTMOV EAX,CR0AND EAX,0x7fffffff ; 使用bit31(禁用分页)OR EAX,0x00000001 ; bit0到1转换(保护模式过渡)MOV CR0,EAXJMP pipelineflush
pipelineflush:MOV AX,1*8 ; 写32bit的段MOV DS,AXMOV ES,AXMOV FS,AXMOV GS,AXMOV SS,AX;bootpack传递MOV ESI,bootpack ; 源MOV EDI,BOTPAK ; 目标MOV ECX,512*1024/4CALL memcpy; 传输磁盘数据; 从引导区开始MOV ESI,0x7c00 ; 源MOV EDI,DSKCAC ; 目标MOV ECX,512/4CALL memcpy; 剩余的全部MOV ESI,DSKCAC0+512 ; 源MOV EDI,DSKCAC+512 ; 目标MOV ECX,0MOV CL,BYTE [CYLS]IMUL ECX,512*18*2/4 ; 除以4得到字节数SUB ECX,512/4 ; IPL偏移量CALL memcpy; 由于还需要asmhead才能完成
; 完成其余的bootpack任务; bootpack启动MOV EBX,BOTPAKMOV ECX,[EBX+16]ADD ECX,3 ; ECX += 3;SHR ECX,2 ; ECX /= 4;JZ skip ; 传输完成MOV ESI,[EBX+20] ; 源ADD ESI,EBXMOV EDI,[EBX+12] ; 目标CALL memcpy
skip:MOV ESP,[EBX+12] ; 堆栈的初始化JMP DWORD 2*8:0x0000001bwaitkbdout:IN AL,0x64AND AL,0x02JNZ waitkbdout ; AND结果不为0跳转到waitkbdoutRETmemcpy:MOV EAX,[ESI]ADD ESI,4MOV [EDI],EAXADD EDI,4SUB ECX,1JNZ memcpy ; 运算结果不为0跳转到memcpyRET
; memcpy地址前缀大小ALIGNB 16
GDT0:RESB 8 ; 初始值DW 0xffff,0x0000,0x9200,0x00cf ; 写32bit位段寄存器DW 0xffff,0x0000,0x9a28,0x0047 ; 可执行的文件的32bit寄存器(bootpack用)DW 0
GDTR0:DW 8*3-1DD GDT0ALIGNB 16
bootpack:
3.加入bootpack.c操作系统代码
这个操作系统实现了一个最简单的功能:让cpu睡眠
void io_hlt(void);void HariMain(void)
{fin:io_hlt(); /* 执行naskfunc.nas里边的_io_hlt()函数。 */goto fin;}
4.加入naskfunc.nas
加入这个文件是因为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睡眠。HLTRET
5.运行结果
本文代码下载地址:https://download.csdn.net/download/u011164819/12981508
这篇关于30天自制操作系统:第三天的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!