Skip to content

Instantly share code, notes, and snippets.

@beiweiqiang
Last active November 23, 2019 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save beiweiqiang/fdfb810c46efe0c091a09e7e6dd26ccb to your computer and use it in GitHub Desktop.
Save beiweiqiang/fdfb810c46efe0c091a09e7e6dd26ccb to your computer and use it in GitHub Desktop.
在 initial program loader 中, 读取 10柱面 * 2磁头 * 18扇区 字节, 每个扇区重试 5 次, 否则跳转 error
; hello-os
; TAB=4
CYLS equ 10
org 0x7c00 ; 指明程序装载地址, 因为前面的内存地址已经被占用了
jmp entry
db 0x90
db "helloipl" ; 启动区的名称 8字节
dw 512 ; 每个扇区的大小 512 字节
db 1 ; cluster 的大小 (1个扇区)
dw 1 ; FAT 的起始位置 (第 1 个扇区开始)
db 2 ; FAT 的个数 (2 个)
dw 224 ; 根目录的大小 (224项)
dw 2880 ; 磁盘大小 (2880 扇区 = 80柱面 * 18扇区 * 2磁头)
db 0xf0 ; 磁盘种类
dw 9 ; FAT 长度 (9 扇区)
dw 18 ; 一个磁道多少个扇区 (18)
dw 2 ; 磁头数量
dd 0 ; 不使用分区
dd 2880 ; 磁盘大小
db 0,0,0x29
dd 0xffffffff
db "hello-osiii" ; 磁盘名称 (11字节)
db "FAT12 " ; 磁盘格式名称 (8字节)
times 18 db 0 ; 空出 18 字节
entry:
mov ax, 0
mov ss, ax
mov sp, 0x7c00
mov ds, ax
mov es, ax
mov ax, 0x0820 ; 放入 es 的 ax, 会自动 * 16, 即 ES:BX = ES * 16 + BX 的内存, 前面的 0x1ff 是给启动区的
mov es, ax
mov ch, 0 ; 柱面 0, 柱面范围: 0 ~ 79
mov dh, 0 ; 磁头 0, 磁头范围: 0 ~ 1
mov cl, 2 ; 扇区 2, 扇区范围: 1 ~ 18, 表示即将读取第 2 个扇区, 现在第 2 个扇区没东西, 直接跑这个 asm 会 error
readloop:
mov si, 0 ; 记录失败次数, 感觉 si 经常用来做累加判断
retry:
mov ah, 0x02 ; ah = 0x02, 表示读盘
mov al, 1 ; 1 个扇区, 表示处理对象的扇区数量
mov bx, 0
mov dl, 0x00 ; A 驱动器
int 0x13 ; 磁盘读, 写, 扇区校验, 寻道. 调用磁盘 BIOS
jnc next ; 进位标志位为 0, 即没有错误, 跳转 next, 准备读取下一个扇面
add si, 1
cmp si, 5
jae error ; >= 5 次, 跳转 error
mov ah, 0x00 ; 准备重置
mov dl, 0x00
int 0x13 ; 重置驱动器
jmp retry
next:
mov ax, es
add ax, 0x0020 ; 把内存地址后移 0x200 (因为 es 会 * 16)
mov es, ax ; 因为没有 add es, 0x20 指令
add cl, 1 ; 下一个扇面
cmp cl, 18
jbe readloop ; 如果 cl <= 18, 继续读取, 扇面编号为 1 ~ 18
mov cl, 1 ; 遍历顺序: 扇区 1~18 -> 磁头 0~1 -> 柱面 0~79
add dh, 1
cmp dh, 2
jb readloop ; 如果 dh (磁头) < 2, 跳转到 readloop
mov dh, 0
add ch, 1 ; 柱面 + 1
cmp ch, CYLS
jb readloop
fin:
hlt ; 使 cpu 停止动作
jmp fin ; 无脑跳 fin
; 下面这是一套展示字符串的逻辑
error:
mov si, msg
putloop:
mov ah, 0x0e ; 为了显示字符, 需要将 AX 高位置为 0e
mov al, [si] ; 把内存 [si] 的内容搬到 al 里
mov bx, 15 ; 颜色 (但是没有效果)
add si, 1
cmp al, 0 ; 如果 al 为 0, 证明内存 [si] 字符串已经结束
je fin ; 如果 al 为 0, 跳转到 fin
int 0x10
jmp putloop
msg:
db "error"
TIMES 0x1fe-($-$$) DB 0 ; 1fe = 510, 还差 2 字节到 512字节 一个扇区
db 0x55, 0xaa ; 这是第 1 个扇区的最后 2 个字节, 55 aa 决定该扇区的开头是启动程序
; 剩余磁盘内容
db 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
times 4600 db 0
db 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
times 1469432 db 0
#! /bin/bash
nasm my.asm -o tos.img
qemu-system-i386 -fda tos.img -boot a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment