30天自制操作系统merk11的第三天

编程

导入了32位模式,终于可以开始使用c语言了

操作系统-merk11的第三天">30天自制操作系统-merk11的第三天

制作真正的IPL

先上参考代码haribote-ipl

目的:读入10个柱面

; 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

;转载请注明出处:https://www.cnblogs.com/merk11/p/15512260.html

切换画面模式&进入32位模式

; haribote-os boot asm

; TAB=4

BOTPAK EQU 0x00280000 ; 加载bootpack

DSKCAC EQU 0x00100000 ; 磁盘缓存的位置

DSKCAC0 EQU 0x00008000 ; 磁盘缓存的位置(实模式)

; 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显卡,320x200x8bit

MOV AH,0x00

INT 0x10

MOV BYTE [VMODE],8 ; 屏幕的模式(参考C语言的引用)

MOV WORD [SCRNX],320

MOV WORD [SCRNY],200

MOV DWORD [VRAM],0x000a0000

; 通过BIOS获取指示灯状态

MOV AH,0x02

INT 0x16 ; keyboard BIOS

MOV [LEDS],AL

; 防止PIC接受所有中断

; AT兼容机的规范、PIC初始化

; 然后之前在CLI不做任何事就挂起

; PIC在同意后初始化

MOV AL,0xff

OUT 0x21,AL

NOP ; 不断执行OUT指令

OUT 0xa1,AL

CLI ; 进一步中断CPU

; 让CPU支持1M以上内存、设置A20GATE

CALL waitkbdout

MOV AL,0xd1

OUT 0x64,AL

CALL waitkbdout

MOV AL,0xdf ; enable A20

OUT 0x60,AL

CALL waitkbdout

; 保护模式转换

[INSTRSET "i486p"] ; 说明使用486指令

LGDT [GDTR0] ; 设置临时GDT

MOV EAX,CR0

AND EAX,0x7fffffff ; 使用bit31(禁用分页)

OR EAX,0x00000001 ; bit0到1转换(保护模式过渡)

MOV CR0,EAX

JMP pipelineflush

pipelineflush:

MOV AX,1*8 ; 写32bit的段

MOV DS,AX

MOV ES,AX

MOV FS,AX

MOV GS,AX

MOV SS,AX

; bootpack传递

MOV ESI,bootpack ; 源

MOV EDI,BOTPAK ; 目标

MOV ECX,512*1024/4

CALL memcpy

; 传输磁盘数据

; 从引导区开始

MOV ESI,0x7c00 ; 源

MOV EDI,DSKCAC ; 目标

MOV ECX,512/4

CALL memcpy

; 剩余的全部

MOV ESI,DSKCAC0+512 ; 源

MOV EDI,DSKCAC+512 ; 目标

MOV ECX,0

MOV CL,BYTE [CYLS]

IMUL ECX,512*18*2/4 ; 除以4得到字节数

SUB ECX,512/4 ; IPL偏移量

CALL memcpy

; 由于还需要asmhead才能完成

; 完成其余的bootpack任务

; bootpack启动

MOV EBX,BOTPAK

MOV ECX,[EBX+16]

ADD ECX,3 ; ECX += 3;

SHR ECX,2 ; ECX /= 4;

JZ skip ; 传输完成

MOV ESI,[EBX+20] ; 源

ADD ESI,EBX

MOV EDI,[EBX+12] ; 目标

CALL memcpy

skip:

MOV ESP,[EBX+12] ; 堆栈的初始化

JMP DWORD 2*8:0x0000001b

waitkbdout:

IN AL,0x64

AND AL,0x02

JNZ waitkbdout ; AND结果不为0跳转到waitkbdout

RET

memcpy:

MOV EAX,[ESI]

ADD ESI,4

MOV [EDI],EAX

ADD EDI,4

SUB ECX,1

JNZ memcpy ; 运算结果不为0跳转到memcpy

RET

; 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-1

DD GDT0

ALIGNB 16

bootpack:

;转载请注明出处:https://www.cnblogs.com/merk11/p/15512260.html

实现HLT

; naskfunc

; TAB=4

[FORMAT "WCOFF"] ; 制作目标文件的模式

[BITS 32] ; 制作32位模式用的机器语言

; 制作目标文件的信息

[FILE "naskfunc.nas"] ; 源文件名信息

GLOBAL _io_hlt ; 程序中包含的函数名

; 以下是实际的函数

[SECTION .text] ; 目标文件中写了这些后再写程序

_io_hlt: ; void io_hlt(void);

HLT

RET

;转载请注明出处:https://www.cnblogs.com/merk11/p/15512260.html

C语言

/* 告诉C编译器,有一个函数在别的文件里 */

void io_hlt(void);

/* 是函数声明却不用{},而用;,这表示的意思是:

函数在别的文件中,你自己找一下 */

void HariMain(void)

{

fin:

io_hlt(); /* 执行naskfunc.nas中的_io_hlt函数 */

goto fin;

}

;转载请注明出处:https://www.cnblogs.com/merk11/p/15512260.html

汇编语言学习

EQU:相当于c语言中的#define

JC:是“jump if carry”的缩写,意思 是如果进位标志(carry flag)是1的话,就跳转。

JB:是“jump if below”的缩写。翻译过 来就是:“如果小于的话,就跳转。”

在BIOS中:

AH=0x02;(读盘) AH=0x03;(写盘)

AH=0x04;(校验) AH=0x0c;(寻道)

AL=处理对象的扇区数;(只能同时处理连续的扇区)

CH=柱面号 &0xff;

CL=扇区号(0-5位)|(柱面号&0x300)>>2;

DH=磁头号;

DL=驱动器号;

ES:BX=缓冲地址;(校验及寻道时不使用)

返回值: (这边的返回值配合了JC的使用)

FLACS.CF == 0:没有错误,AH==0

FLAGS.CF == 1:有错误,错误号码存入AH内(与重置(reset)功能一样)

设置显卡模式:

AH=0x00;

AL=模式:(省略了一些不重要的画面模式)

0x03:16色字符模式,80 × 25

0x12:VGA 图形模式,640 × 480 × 4位彩色模式,独特的4面存储模式

0x13:VGA 图形模式,320 × 200 × 8位彩色模式,调色板模式

0x6a:扩展VGA 图形模式,800 × 600 × 4位彩色模式,独特的4面存储模式 (有的显卡不支持这个模式)

返回值:无

计算机组成学习

软盘

沿半径方向分割成18个扇区

按同心圆方式分割成80个柱面

由于磁盘正反两面都能记录数据,所以有两个磁头

一般向一个空软盘保存文件时

(1) 文件名会写在0x002600以后的地方;

(2) 文件的内容会写在0x004200以后的地方。

编译原理学习

自己的理解:

.c文件首先gcc编译器的处理下,生成.gas文件,

.gas文件接着生成.obj目标文件

.obj目标文件在通过link后生成.bim文件

.bim虽然是二进制映像文件但是缺少一下必要的文件头和压缩

所以还需加工成.hrb真正的完整的机器语言文件

笔者对编译过程解释见原著:

首先,使用cc1.exe从bootpack.c生成bootpack.gas。

第二步,使用gas2nask.exe从bootpack.gas生成bootpack.nas。

第三步,使用nask.exe从bootpack.nas生成bootpack.obj。

第四步,使用obi2bim.exe从bootpack.obj生成bootpack.bim。

最后,使用bim2hrb.exe从bootpack.bim生成bootpack.hrb。

这样就做成了机器语言,再使用copy指令将asmhead.bin与bootpack.hrb单纯结合到起来, 就成了haribote.sys。

以上是 30天自制操作系统merk11的第三天 的全部内容, 来源链接: utcz.com/z/520025.html

回到顶部