Professional Documents
Culture Documents
1) Asmhead.asm
; haribote-os
; 有关 BOOT_INFO
CYLS EQU 0x0ff0 ; 设置启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率 X
SCRNY EQU 0x0ff6 ; 分辨率 Y
VRAM EQU 0x0ff8 ; 图像缓冲区的起始位置
[SECTION .btext]
[BITS 16]
entry:
; 设置屏幕模式
MOV AL, 0x13 ; VGA 显卡,320x200x8 bit
MOV AH, 0x00
INT 0x10
CLI
; 切换到保护模式
; NASM 不支持 INSTRSET 命令
; [INSTRSET "i486p"] ; 使用 486 指令
LGDT [GDTR0] ; 设置临时 GDT
MOV EAX, CR0
AND EAX, 0x7fffffff ; 禁用分页
OR EAX, 0x00000001 ; 开启保护模式
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, 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
; 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
MOV ESP, 0xffff
JMP DWORD 2*8:0x00000000
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 地址前缀大小
ALIGN 16
GDT0:
RESB 8 ; 初始值
DW 0xffff, 0x0000, 0x9200, 0x00cf ; 可写的 32 位段寄存器
DW 0xffff, 0x0000, 0x9a28, 0x0047 ; 可执行的文件的 32 位寄存器
DW 0
GDTR0:
DW 8*3-1
DD GDT0
ALIGN 16
bootpack:
2) Bootpack.c
void io_hlt(void);
; [FORMAT "WCOFF"]
[BITS 32]
[SECTION .text]
io_hlt: ; void io_hlt(void);
HLT
RET
4) Haribote.ld
ENTRY( entry )
SECTIONS
{
. = 0xc200;
.btext : { *(.btext) }
.text : { *(.text) }
.data : { *(.data) }
}
5) Ipl.asm
; hello-os
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
next:
MOV AX, ES ; 把内存地址后移 0x200
ADD AX, 0x0020
MOV ES, AX ; 实现 ES += 0x0020 的目的
; 扇区范围 1~18
ADD CL, 1 ; 扇区加 1
CMP CL, 18 ; 扇区是否达到 18
JBE readloop ; 小于等于 18 扇区则跳转到 readloop
MOV DH, 0
; 柱面范围 0 ~ 79
ADD CH, 1
CMP CH, CYLS
JB readloop ; 读取指定数量的柱面,未达到 CYLS 则跳转
readloop
; 读取完毕,跳转到 haribote.sys 执行
MOV [0x0ff0], CH ; 记下 IPL 读了多远(谷歌翻译自 IPL がどこま
で読んだのかをメモ)
JMP 0xc200
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 ; 两个换行
DB "load error"
DB 0x0a ; 换行
DB 0
ifndef GCCPREFIX
GCCPREFIX :=
endif
AS := nasm
CC := $(GCCPREFIX)gcc
LD := $(GCCPREFIX)ld
OBJCOPY := $(GCCPREFIX)objcopy
CFLAGS := -Wall -m32 -fno-pie
QEMU := qemu-system-i386
QEMU_FLAGS :=
ifdef DEBUG
QEMU_FLAGS += -gdb tcp::1234 -S
CFLAGS += -g
endif
ipl.bin:
$(AS) -f bin ipl.asm -o ipl.bin -l ipl.lst
asmhead.bin:
$(AS) -f elf asmhead.asm -o asmhead.bin -l asmhead.lst
bootpack.bin:
$(CC) $(CFLAGS) -c bootpack.c -o bootpack.bin
func.bin:
$(AS) -f elf func.asm -o func.bin -l func.lst
haribote.sys: asmhead.bin bootpack.bin func.bin
$(LD) -m elf_i386 --oformat binary asmhead.bin bootpack.bin func.bin -o haribote.sys -T
haribote.ld
clean:
rm -rf *.bin
rm -rf *.sys
rm -rf *.obj
rm -rf *.lst
rm -rf $(IMG)
.PHONY:
all