Good in study, attitude and health

操作系统-从零开始编写

  • 教程:https://github.com/ruiers/os-tutorial-cn

01-引导扇区


02-引导打印

mov ah, 0x0e      ; 设置功能号为 0x0E,TTY 模式输出字符
mov al, 'H'       ; 将字符 'H' 的 ASCII 码加载到 AL 寄存器
int 0x10          ; 调用 BIOS 中断 0x10,显示字符
mov al, 'e'
int 0x10
mov al, 'l'
int 0x10
int 0x10 ; 'l' is still on al, remember?
mov al, 'o'
int 0x10

jmp $ ; jump to current address = infinite loop

; padding and magic number
times 510 - ($-$$) db 0
dw 0xaa55
  • 输出字符到屏幕

    • AH = 0x0E:表示调用 BIOS 的 0x10 中断,用于显示字符(TTY 模式)。
    • AL:要显示的字符存储在 AL 寄存器中。
    • int 0x10:BIOS 提供的显示服务中断。0x10 是视频服务的功能号。
    • 每调用一次 int 0x10,就会将 AL 中的字符显示在屏幕上。
  • 显示 “Hello”

    mov al, 'e'
    int 0x10          ; 显示 'e'
    
    mov al, 'l'
    int 0x10          ; 显示 'l'
    
    int 0x10          ; 再次显示 'l',因为 AL 仍然是 'l'
    
    mov al, 'o'
    int 0x10          ; 显示 'o'
    
    • 这几行代码逐步将 “Hello” 的每个字符显示在屏幕上。
    • 第一次显示 ‘l’ 后,未修改 AL,直接再次调用 int 0x10 会再次显示 ‘l’。
  • 无限循环

    jmp $ ; $ 表示当前地址,跳转到自身 = 无限循环
    
  • 填充和魔术数字

    times 510 - ($-$$) db 0
    dw 0xaa55
    
    • times 指令:用于填充字节到指定长度。$:表示当前地址。$$:表示文件的起始地址。$-$$:表示当前代码(已经写的)的大小。times 510 - ($-$$) db 0:将文件填充到 510 字节(一个扇区的大小为 512 字节,保留最后的 2 字节给魔术数字)。填充内容为 0。
    • dw 0xaa55:定义双字(2 字节)的值 0xAA55。0xAA55 是启动扇区的魔术数字,BIOS 通过检查这个值来判断该扇区是否是一个有效的启动扇区。如果最后两字节不是 0xAA55,BIOS 会认为这个扇区不可引导。

代码执行流程

  1. BIOS 加载扇区:BIOS 在启动时,会读取磁盘的第一个扇区(512 字节)到内存的 0x7C00 地址。检查最后两字节是否为 0xAA55,如果是,则跳转到加载地址执行。
  2. 显示 “Hello”:程序通过调用 int 0x10 的功能号 0x0E,逐字输出 “Hello”。
  3. 进入无限循环:程序最后通过 jmp $ 进入无限循环,防止后续执行未知指令。

补充知识


times 指令,NASM 汇编器中的伪指令,用于重复生成指定数量的指令或数据。

times <count> <value>
  • $ 和 $$ 符号

    • $:表示当前地址。
    • $$:表示当前段的起始地址(通常是文件或代码段的开始位置)。
    • $ - $$:计算从段的起始地址到当前地址的偏移量,表示当前代码的大小。
  • db 0

    • db(Define Byte):定义一个字节。
    • db 0:定义一个值为 0 的字节。
    • 在这里,db 0 用作填充值,填充代码区域未使用的部分。