.code16
.globl _start
_start:
ljmpw $0x07c0, $1f
1: xorw %ax, %ax
movw %ax, %ss
movw $0x7c00, %sp
callw interrupt_init
callw register_disk_interrupt
callw enable_disk_interrupt
# 全局变量初始化
# flag = 0;
movb $0, %cs:0 # 就把它放在这里,这不会有任何问题
# 读取从扇区 0 开始的 8 个扇区到 ds:si 指定的位置
movw $0x07e0, %ax
movw %ax, %ds
xorw %si, %si
movw $8, %cx
xorw %bx, %bx
callw read_sect
movw $0xb800, %ax
movw %ax, %ds
movb o', 0x06e0
movb k', 0x06e2
movb $0x04, 0x06e1
movb $0x04, 0x06e3
cli
hlt
3: jmp 3b
# void read_sect(uint8_t *buff, size_t start_sect, size_t count);
# buff -> ds:si
# start_sect -> bx
# count -> cx
read_sect:
pushw %ax
pushw %cx
pushw %dx
pushw %si
pushw %bx
# 读取 count 个扇区
movb %cl, %al
movw $0x01f2, %dx
outb %al, (%dx)
# 发送逻辑扇区号
movb %bl, %al
movw $0x01f3, %dx
outb %al, (%dx)
movb %bh, %al
movw $0x01f4, %dx
outb %al, (%dx)
movb $0, %al
movw $0x01f5, %dx
outb %al, (%dx)
movb $0xe0, %al # 主盘,LBA 模式
movw $0x01f6, %dx
outb %al, (%dx)
# 发送读命令
movb $0x20, %al
movw $0x01f7, %dx
outb %al, (%dx)
movw %cx, %bx
# 等待硬盘准备好
1: movb %cs:0, %al
cmpb $1, %al
jne 1b
movb $0, %cs:0
# 从硬盘读取数据
xorw %cx, %cx
movw $0x01f0, %dx
2: inw (%dx), %ax
movw %ax, (%si)
addw $2, %si
incw %cx
cmpw $256, %cx # 512 字节,256 个字
jb 2b
decw %bx
cmpw $0, %bx
jne 1b
popw %bx
popw %si
popw %dx
popw %cx
popw %ax
retw
# void interrupt_init(void);
interrupt_init:
cli
pushw %ax
pushw %cx
pushw %dx
pushw %si
pushw %ds
# ICW1: 边沿触发/级联方式
movb $0x11, %al
movw $0x20, %dx
outb %al, (%dx)
# ICW2: 起始中断向量
movb $0x20, %al
movw $0x21, %dx
outb %al, (%dx)
# ICW3: 从片级联到IR2
movb $0x04, %al
movw $0x21, %dx
outb %al, (%dx)
# ICW4: 非总线缓存/特殊全嵌套/非自动结束
movb $0x11, %al
movw $0x21, %dx
outb %al, (%dx)
# ICW1: 边沿触发/级联方式
movb $0x11, %al
movw $0xa0, %dx
outb %al, (%dx)
# ICW2: 起始中断向量
movb $0x28, %al
movw $0xa1, %dx
outb %al, (%dx)
# ICW3: 从片级联到IR2
movb $0x02, %al
movw $0xa1, %dx
outb %al, (%dx)
# ICW4: 非总线缓存/普通全嵌套/非自动结束
movb $0x01, %al
movw $0xa1, %dx
outb %al, (%dx)
# 设置默认中断
xorw %cx, %cx
movw %cx, %ds
movw $0x20 * 4, %si
movw $ignore_interrupt, %ax
movw %cs, %dx
1: movw %ax, (%si)
movw %dx, 2(%si)
addw $4, %si
incw %cx
cmpw $16, %cx
jb 1b
popw %ds
popw %si
popw %dx
popw %cx
popw %ax
sti
retw
# void ignore_interrupt(void);
ignore_interrupt:
pushw %ax
pushw %dx
# 发送 OCW2
movb $0x20, %al
movw $0xa0, %dx
outb %al, (%dx)
movb $0x20, %al
movw $0x20, %dx
outb %al, (%dx)
popw %dx
popw %ax
iretw
# void register_disk_interrupt(void);
register_disk_interrupt:
cli
pushw %ax
pushw %dx
pushw %ds
xorw %ax, %ax
movw %ax, %ds
movw $disk_interrupt, %ax
movw %cs, %dx
# IRQ14
movw %ax, 0xb8
movw %dx, 0xba
popw %ds
popw %dx
popw %ax
sti
retw
# void disk_interrupt(void);
disk_interrupt:
pushw %ax
pushw %dx
# 读取硬盘状态
movw $0x01f7, %dx
inb (%dx), %al
andb $0x88, %al
cmpb $0x08, %al
jne 1f
# 硬盘数据准备好了
# flag = 1;
movb $1, %cs:0
1:
# 发送 OCW2
movb $0x20, %al
movw $0xa0, %dx
outb %al, (%dx)
movb $0x20, %al
movw $0x20, %dx
outb %al, (%dx)
popw %dx
popw %ax
iretw
# void enable_disk_interrupt(void);
enable_disk_interrupt:
pushw %ax
pushw %dx
movb $0x00, %al
movw $0x03f6, %dx
outb %al, (%dx)
popw %dx
popw %ax
retw