第3天 进入32位模式并导入C语言

  • 指令JC —— “jump if carry”的缩写,意思是如果进位标志(carry flag)是1的话,就跳转
  • INT 0x13—— 调用BIOS的0x13号函数,用来进行磁盘读、写,扇区校验(verify),以及寻道(seek)
  • AH=0x02;(读盘)AH=0x03;(写盘)AH=0x04;(校验)AH=0x0c;(寻道)
  • AL=处理对象的扇区数;(只能同时处理连续的扇区)
  • CH=柱面号 &0xff;
  • CL=扇区号(0-5位)|(柱面号&0x300)* * 2;
  • DH=磁头号;
  • DL=驱动器号;
    在有多个软盘驱动器的时候,用磁盘驱动器号来指定从哪个驱动器的软盘上读取数据。现在的电脑,基本都只有1个软盘驱动器,指定0号就行了
  • ES:BX=缓冲地址;(校验及寻道时不使用)
  • 返回值:FLACS.CF==0:没有错误,AH==0
    FLAGS.CF==1:有错误,错误号码存入AH内(与重置(reset)功能一样)
    这里FLAGS.CF表示进位标志,也就是说调用这个函数之后,如果没有错,进位标志就是0;如果有错,进位标志就是1。
    AH=0x00,DL=0x00,INT 0x13 这是“系统复位”。它的功能是复位软盘状态,再读一次。
  • JNC —— “Jump if not carry”进位标志是0的话就跳转
  • JAE —— “Jump if above or equal” 大于或等于时跳转
  • JBE——“jump if below or equal” 小于等于则跳转
  • JB —— “jump if below” 如果小于的话,就跳转。
  • EQU指令—— “equal” 相当于C语言的#define命令,用来声明常数。“CYLS EQU 10”意思是“CYLS = 10”。
    软盘的结构:
    在这里插入图片描述
  • 软盘拆开后可以看到,中间有一个8厘米的黑色圆盘,那是一层薄薄的磁性胶片。从外向内,
    一圈一圈圆环状的区域,分别称为柱面0,柱面1,……,柱面79。一共有80个柱面。柱面
    在英文中是cylinder。
  • 磁头是个针状的磁性设备,既可以从软盘正面接触磁盘,也可以从软盘背面接触磁盘。与光盘不同,软盘磁盘是两面都能记录数据的。因此我们有正面和反面两个磁头,分别是磁头0号和磁头1号。
  • 扇区在磁盘的这个圆环上,还能记录很多位信息,按照整个圆环为单位读写的话,实在有点多,所以
    我们又把这个圆环均等地分成了几份。软盘分为18份,每一份称为一个扇区。一个圆环有18个扇区,分别称为扇区1、扇区2、……扇区18。扇区在英文中是sector,意思是指领域、扇形。

综上所述,1张软盘有80个柱面,2个磁头,18个扇区,且一个扇区有
512字节。所以,一张软盘的容量是:
80 ∗ 2 ∗ 18 ∗ 512 = 1474560 B y t e = 1440 K B 80*2*18*512 =1474560Byte = 1440KB 80218512=1474560Byte=1440KB
含有IPL(Initial ProgramLoader,启动程序装载器)的启动区,位于C0-H0-S1(柱面0,磁头0,扇区1的缩写),下一个扇区是C0-H0-S2。这次我们想要装载的就是这个扇区。

缓冲区地址:是个内存地址,表明我们要把从软盘上读出的数据装载到内存的哪个位置。ES:BX代表ES×16+BX的内存地址,这样如果在ES里代入0xffff,在BX里也代入0xffff,就是1114095(0xffff*16+0xffff)字节,也就是说可以指定1M以内的内存地址了,这里指定指定了ES=0x0820,BX=0,软盘的数据将被装载到内存中0x8200到0x83ff的地方(512字节)。
在这里插入图片描述

程序中必须指定段寄存器,如果省略的话,使用“DS:”作为段寄存器,例如:

MOV CX,[1234]   =>  MOV CX,[DS:1234]
MOV AL,[SI]     =>  MOV AL,[DS:SI]

装载下一个512字节的ipl.nas为:

; haribote-ipl
; TAB=4

		ORG		0x7c00			; 指明程序的装载地址

; 以下这段是标准FAT12格式软盘专用的代码

		JMP		entry
		DB		0x90
		DB		"HARIBOTE"		; 启动区的名称可以是任意的字符串(8字节)
		DW		512				; 每个扇区(sector)的大小(必须为512字节)
		DB		1				; 簇(cluster)的大小(必须为1个扇区)
		DW		1				; FAT12的起始位置(一般从第一个扇区开始)
		DB		2				; FAT的个数(必须为2)
		DW		224				; 根目录的大小(一般设成224项)
		DW		2880			; 该磁盘的大小(必须是2880扇区)
		DB		0xf0			; 磁盘的种类(必须是0xf0)
		DW		9				; FAT的长度(必须是9扇区)
		DW		18				; 1个磁道(track)有几个扇区(必须是18)
		DW		2				; 磁头数(必须是2)
		DD		0				; 不使用分区,必须是0
		DD		2880			; 重写一次磁盘大小
		DB		0,0,0x29		; 意义不明,固定
		DD		0xffffffff		; (可能是)卷标号码
		DB		"HARIBOTEOS "	; 磁盘的名称(11字节)
		DB		"FAT12   "		; 磁盘格式名称
		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

		MOV		AH,0x02			; AH=0x02 : 读盘
		MOV		AL,1			; 1个扇区
		MOV		BX,0
		MOV		DL,0x00			; A驱动器
		INT		0x13			; 调用磁盘BIOS
		JC		error

; 虽然读完了,但是因为没有要做的事情所以睡了

fin:
		HLT						; 让CPU停止,等待指令
		JMP		fin				; 无限循环

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
msg:
		DB		0x0a, 0x0a		; 换行2次
		DB		"load error"
		DB		0x0a			; 换行
		DB		0

		RESB	0x7dfe-$		; 填写0x00,直到 0x7dfe

		DB		0x55, 0xaa

Makefile:


# 默认动作

default :
	../z_tools/make.exe img

# 文件生成规则

ipl.bin : ipl.nas Makefile
	../z_tools/nask.exe ipl.nas ipl.bin ipl.lst

helloos.img : ipl.bin Makefile
	../z_tools/edimg.exe   imgin:../z_tools/fdimg0at.tek \
		wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img

# 命令

asm :
	../z_tools/make.exe -r ipl.bin

img :
	../z_tools/make.exe -r helloos.img

run :
	../z_tools/make.exe img
	copy helloos.img ..\z_tools\qemu\fdimage0.bin
	../z_tools/make.exe -C ../z_tools/qemu

install :
	../z_tools/make.exe img
	../z_tools/imgtol.com w a: helloos.img

clean :
	-del ipl.bin
	-del ipl.lst

src_only :
	../z_tools/make.exe clean
	-del helloos.img

如果考虑读取过程中出错,重试5次,

  1. 使用SI记录错误次数,超过5次则显示error
  2. 每次读取失败都需要复位软盘状态(AH=0x00)
    则修改后的ipl.nas为:
; haribote-ipl
; TAB=4

        ORG        0x7c00            ; 指明程序的装载地址

; 以下这段是标准FAT12格式软盘专用的代码

        JMP        entry
        DB        0x90
        DB        "HARIBOTE"            ; 启动区的名称可以是任意的字符串(8字节)
        DW        512                   ; 每个扇区(sector)的大小(必须为512字节)
        DB        1                     ; 簇(cluster)的大小(必须为1个扇区)
        DW        1                     ; FAT12的起始位置(一般从第一个扇区开始)
        DB        2                     ; FAT的个数(必须为2)
        DW        224                   ; 根目录的大小(一般设成224项)
        DW        2880                  ; 该磁盘的大小(必须是2880扇区)
        DB        0xf0                  ; 磁盘的种类(必须是0xf0)
        DW        9                     ; FAT的长度(必须是9扇区)
        DW        18                    ; 1个磁道(track)有几个扇区(必须是18)
        DW        2                     ; 磁头数(必须是2)
        DD        0                     ; 不使用分区,必须是0
        DD        2880                  ; 重写一次磁盘大小
        DB        0,0,0x29              ; 意义不明,固定
        DD        0xffffffff            ; (可能是)卷标号码
        DB        "HARIBOTEOS "         ; 磁盘的名称(11字节)
        DB        "FAT12   "            ; 磁盘格式名称
        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
        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              ; 没出错的话跳转到fin
        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
        
        

; 虽然读完了,但是因为没有要做的事情所以睡了

fin:
        HLT                        ; 让CPU停止,等待指令
        JMP        fin             ; 无限循环

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
msg:
        DB        0x0a, 0x0a       ; 换行2次
        DB        "load error"
        DB        0x0a             ; 换行
        DB        0

        RESB    0x7dfe-$           ; 填写0x00,直到 0x7dfe

        DB        0x55, 0xaa

如果需要读18个扇区,
1、读下一个扇区需要将缓冲地址+512(0x200),这里可以改变段寄存器的大小
2、CL表示扇区号
3、SI为重试次数,所以每次读一个新的扇区需要将SI清0
修改后代码如下:

; haribote-ipl
; TAB=4

        ORG        0x7c00            ; 指明程序的装载地址

; 以下这段是标准FAT12格式软盘专用的代码

        JMP        entry
        DB        0x90
        DB        "HARIBOTE"            ; 启动区的名称可以是任意的字符串(8字节)
        DW        512                   ; 每个扇区(sector)的大小(必须为512字节)
        DB        1                     ; 簇(cluster)的大小(必须为1个扇区)
        DW        1                     ; FAT12的起始位置(一般从第一个扇区开始)
        DB        2                     ; FAT的个数(必须为2)
        DW        224                   ; 根目录的大小(一般设成224项)
        DW        2880                  ; 该磁盘的大小(必须是2880扇区)
        DB        0xf0                  ; 磁盘的种类(必须是0xf0)
        DW        9                     ; FAT的长度(必须是9扇区)
        DW        18                    ; 1个磁道(track)有几个扇区(必须是18)
        DW        2                     ; 磁头数(必须是2)
        DD        0                     ; 不使用分区,必须是0
        DD        2880                  ; 重写一次磁盘大小
        DB        0,0,0x29              ; 意义不明,固定
        DD        0xffffffff            ; (可能是)卷标号码
        DB        "HARIBOTEOS "         ; 磁盘的名称(11字节)
        DB        "FAT12   "            ; 磁盘格式名称
        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              ; 没出错的话跳转到fin
        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
        ADD         AX,0x0020        ;下一个扇区在内存中的缓存
        MOV         ES,AX 
        ADD         CL,1
        CMP         CL,18
        JBE         readloop
        
        

; 虽然读完了,但是因为没有要做的事情所以睡了

fin:
        HLT                        ; 让CPU停止,等待指令
        JMP        fin             ; 无限循环

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
msg:
        DB        0x0a, 0x0a       ; 换行2次
        DB        "load error"
        DB        0x0a             ; 换行
        DB        0

        RESB    0x7dfe-$           ; 填写0x00,直到 0x7dfe

        DB        0x55, 0xaa

读入10个柱面:
1、读完第一个18个扇区后,需要将扇区(CL)从1开始计数,这是因为第一个扇区为启动区;
2、软盘分为上下两个磁头,所以需要将上下两个磁头的数据都读出来(DH)
3、柱面(CH)读取从1~10
代码如下

; haribote-ipl
; TAB=4

        CYLS	EQU		10
        ORG        0x7c00            ; 指明程序的装载地址

; 以下这段是标准FAT12格式软盘专用的代码

        JMP        entry
        DB        0x90
        DB        "HARIBOTE"            ; 启动区的名称可以是任意的字符串(8字节)
        DW        512                   ; 每个扇区(sector)的大小(必须为512字节)
        DB        1                     ; 簇(cluster)的大小(必须为1个扇区)
        DW        1                     ; FAT12的起始位置(一般从第一个扇区开始)
        DB        2                     ; FAT的个数(必须为2)
        DW        224                   ; 根目录的大小(一般设成224项)
        DW        2880                  ; 该磁盘的大小(必须是2880扇区)
        DB        0xf0                  ; 磁盘的种类(必须是0xf0)
        DW        9                     ; FAT的长度(必须是9扇区)
        DW        18                    ; 1个磁道(track)有几个扇区(必须是18)
        DW        2                     ; 磁头数(必须是2)
        DD        0                     ; 不使用分区,必须是0
        DD        2880                  ; 重写一次磁盘大小
        DB        0,0,0x29              ; 意义不明,固定
        DD        0xffffffff            ; (可能是)卷标号码
        DB        "HARIBOTEOS "         ; 磁盘的名称(11字节)
        DB        "FAT12   "            ; 磁盘格式名称
        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              ; 没出错的话跳转到fin
        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
        ADD         AX,0x0020        ;下一个扇区在内存中的缓存
        MOV         ES,AX 
        ADD         CL,1
        CMP         CL,18
        JBE         readloop
        MOV         CL,1
        ADD         DH,1
        CMP         DH,2
        JB          readloop
        MOV         DH,0
        ADD         CH,1
        CMP         CH,CYLS
        JB         readloop
        
        

; 虽然读完了,但是因为没有要做的事情所以睡了

fin:
        HLT                        ; 让CPU停止,等待指令
        JMP        fin             ; 无限循环

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
msg:
        DB        0x0a, 0x0a       ; 换行2次
        DB        "load error"
        DB        0x0a             ; 换行
        DB        0

        RESB    0x7dfe-$           ; 填写0x00,直到 0x7dfe

        DB        0x55, 0xaa

着手开发操作系统

新建文件haribote.nas:

fin:
		HLT
		JMP		fin

用nask编译,输出成hanbote.sys:

haribote.sys : haribote.nas Makefile
	$(NASK) haribote.nas haribote.sys haribote.lst

接下来,将这个文件保存到磁盘映像haribote.img里:

#磁盘映像管理工具 edimg.exe,先读入一个空白的磁盘映像文件,然后在开头写入
#ipl.bin的内容,最后将结果输出为名为helloos.img的磁盘映像文件。
haribote.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

完整的Makefile如下:

TOOLPATH = ../z_tools/
MAKE     = $(TOOLPATH)make.exe -r
NASK     = $(TOOLPATH)nask.exe
EDIMG    = $(TOOLPATH)edimg.exe
IMGTOL   = $(TOOLPATH)imgtol.com
COPY     = copy
DEL      = del

# 默认动作

default :
	$(MAKE) img

# 文件生成规则

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

haribote.sys : haribote.nas Makefile
	$(NASK) haribote.nas haribote.sys haribote.lst

#磁盘映像管理工具 edimg.exe,先读入一个空白的磁盘映像文件,然后在开头写入
#ipl.bin的内容,最后将结果输出为名为helloos.img的磁盘映像文件。
haribote.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

# 命令

img :
	$(MAKE) haribote.img

run :
	$(MAKE) img
	$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
	$(MAKE) -C ../z_tools/qemu

install :
	$(MAKE) img
	$(IMGTOL) w a: haribote.img

clean :
	-$(DEL) ipl.bin
	-$(DEL) ipl.lst
	-$(DEL) haribote.sys
	-$(DEL) haribote.lst

src_only :
	$(MAKE) clean
	-$(DEL) haribote.img

使用make img制作镜像文件,使用二进制工具打开haribote.img发现,在0x2600处保存haribote.sys的文件名
在这里插入图片描述
在0x4200保存haribote.sys的文件内容:
在这里插入图片描述
所以一般向一个空软盘保存文件时,

  1. 文件名会写在0x002600以后的地方;
  2. 文件的内容会写在0x004200以后的地方。

这样我们就可以将操作系统本身的内容写到名为haribote.sys中,再将它保存到磁盘映像,然后再从启动区执行haribote.sys。
在这里插入图片描述
0x8000 - 0x81FF这512字节是留给(copy)启动区的,要将启动区的内容读到那里。0x7c00 - 0x7DFF(512字节)用于启动区。
那么要怎样才能执行磁盘映像上位于0x004200号地址的程序呢?
程序是从启动区开始,把磁盘上的内容装载到内存0x8000号地址,所以磁盘0x4200处的内容就应该位于内存0x8000+0x4200=0xc200号地址。
这样的话,我们就往haribote.nas里加上ORG 0xc200,然后在ipl.nas处理的最后加上JMP 0xc200这个指令。
haribote.nas

; haribote-os
; TAB=4

		ORG		0xc200			; 指明程序的装载地址
fin:
		HLT
		JMP		fin

ipl.nas

; haribote-ipl
; TAB=4

        CYLS	EQU		10
        ORG        0x7c00            ; 指明程序的装载地址

; 以下这段是标准FAT12格式软盘专用的代码

        JMP        entry
        DB        0x90
        DB        "HARIBOTE"            ; 启动区的名称可以是任意的字符串(8字节)
        DW        512                   ; 每个扇区(sector)的大小(必须为512字节)
        DB        1                     ; 簇(cluster)的大小(必须为1个扇区)
        DW        1                     ; FAT12的起始位置(一般从第一个扇区开始)
        DB        2                     ; FAT的个数(必须为2)
        DW        224                   ; 根目录的大小(一般设成224项)
        DW        2880                  ; 该磁盘的大小(必须是2880扇区)
        DB        0xf0                  ; 磁盘的种类(必须是0xf0)
        DW        9                     ; FAT的长度(必须是9扇区)
        DW        18                    ; 1个磁道(track)有几个扇区(必须是18)
        DW        2                     ; 磁头数(必须是2)
        DD        0                     ; 不使用分区,必须是0
        DD        2880                  ; 重写一次磁盘大小
        DB        0,0,0x29              ; 意义不明,固定
        DD        0xffffffff            ; (可能是)卷标号码
        DB        "HARIBOTEOS "         ; 磁盘的名称(11字节)
        DB        "FAT12   "            ; 磁盘格式名称
        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              ; 没出错的话跳转到fin
        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
        ADD         AX,0x0020        ;下一个扇区在内存中的缓存
        MOV         ES,AX 
        ADD         CL,1
        CMP         CL,18
        JBE         readloop
        MOV         CL,1
        ADD         DH,1
        CMP         DH,2
        JB          readloop
        MOV         DH,0
        ADD         CH,1
        CMP         CH,CYLS
        JB         readloop
        
        

; haribote.sys执行

        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       ; 换行2次
        DB        "load error"
        DB        0x0a             ; 换行
        DB        0

        RESB    0x7dfe-$           ; 填写0x00,直到 0x7dfe

        DB        0x55, 0xaa

AH=00/INT 10H 是用来设定显示模式的服务程序,AL 寄存器表示欲设定的模式:

  • 0x03:16色字符模式,80 × 25
  • 0x12:VGA 图形模式,640 × 480 × 4位彩色模式,独特的4面存储模式
  • 0x13:VGA 图形模式,320 × 200 × 8位彩色模式,调色板模式
  • 0x6a:扩展VGA 图形模式,800 × 600 × 4位彩色模式,独特的4面存储模式(有的显卡不支持这个模式)

返回值:无
这种画面模式下显卡内存(video RAM)是0xa0000~0xaffff的64KB

键盘I/O中断调用(INT 16H)
格式:

    MOV AH, 02H
    INT 16H

功能:检查键盘上各特殊功能键的状态。执行后,各种特殊功能键的状态放入AL寄存器中

如果我们想设置显卡模式为0x13,从BIOS获取键盘状态(所谓键盘状态,是指NumLock是ON还是OFF等这些状态。)

haribote.nas

; haribote-os
; TAB=4

; 有关BOOT_INFO
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        0xc200            ; 这个程序将要被装载到内存的什么地方呢?

        MOV        AL,0x13            ; VGA 显卡,320x200x8位彩色
        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

fin:
        HLT
        JMP        fin

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值