lnlidawei

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

【asm】:几个重要程序——汇编语言

【asm】:几个重要程序——汇编语言

 

 

 

 

一、基础说明

 

  1、【目录】:几个重要程序

    ----【CPU的模式切换:实模式(16位)——>保护模式(32位)】

    ----【CPU的模式切换三级跳:实模式(16位)——>保护模式(32位)——>长模式(64位)】(备注:这个程序无法通过编译,原因是程序中包含内存越界访问)

 

 

 

二、几个重要的程序

 

 

  1、  CPU模式切换:实模式——>保护模式

[wit@ubuntu:src]$ cat boot.asm 
[BITS 16]
[ORG 0x7C00]

start:
    cli                 ; 关中断
    lgdt [gdt_desc]     ; 加载 GDT

    ; 切换到保护模式
    mov eax, cr0
    or eax, 1           ; 设置 PE 位
    mov cr0, eax
    
    ; 远跳转刷新流水线
    jmp 0x08:code32

[BITS 32]
code32:
    mov ax, 0x10        ; 设置数据段
    mov ds, ax
    mov ss, ax
    mov esp, 0x90000    ; 设置栈顶

    ; 此时可以检查 CR0 确认状态
    mov eax, cr0        ; eax 中现在包含 CR0 的值,PE 位应为 1

    ; 死循环,防止跑飞
    hlt
    jmp $

; GDT 定义
gdt_start:
    dq 0x0000000000000000 ; 空描述符
gdt_code:
    dw 0xFFFF             ; Limit (low)
    dw 0x0000             ; Base (low)
    db 0x00               ; Base (mid)
    db 10011010b          ; Access byte (Present, Ring 0, Code, Executable)
    db 11001111b          ; Flags + Limit (high)
    db 0x00               ; Base (high)
gdt_data:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 10010010b          ; Access byte (Present, Ring 0, Data, Writable)
    db 11001111b
    db 0x00
gdt_end:

gdt_desc:
    dw gdt_end - gdt_start - 1 ; GDT 界限
    dd gdt_start               ; GDT 基地址

times 510-($-$$) db 0
dw 0xAA55                    ; 引导签名

 

 

2、  内存管理:GDT和段选择子(CPU从实模式到保护模式切换的关键)

[wit@ubuntu:src]$ cat  boot.asm 
[BITS 16]
[ORG 0x7C00]

start:
    cli                 ; 关中断
    lgdt [gdt_desc]     ; 加载 GDT

    ; 切换到保护模式
    mov eax, cr0
    or eax, 1           ; 设置 PE 位
    mov cr0, eax
    
    ; 远跳转刷新流水线
    jmp 0x08:code32

[BITS 32]
code32:
    mov ax, 0x10        ; 设置数据段
    mov ds, ax
    mov ss, ax
    mov esp, 0x90000    ; 设置栈顶

    ; 此时可以检查 CR0 确认状态
    mov eax, cr0        ; eax 中现在包含 CR0 的值,PE 位应为 1

    ; 死循环,防止跑飞
    hlt
    jmp $

; GDT 定义
gdt_start:
    dq 0x0000000000000000 ; 空描述符
gdt_code:
    dw 0xFFFF             ; Limit (low)
    dw 0x0000             ; Base (low)
    db 0x00               ; Base (mid)
    db 10011010b          ; Access byte (Present, Ring 0, Code, Executable)
    db 11001111b          ; Flags + Limit (high)
    db 0x00               ; Base (high)
gdt_data:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 10010010b          ; Access byte (Present, Ring 0, Data, Writable)
    db 11001111b
    db 0x00
gdt_end:

gdt_desc:
    dw gdt_end - gdt_start - 1 ; GDT 界限
    dd gdt_start               ; GDT 基地址

times 510-($-$$) db 0
dw 0xAA55                    ; 引导签名

 

 

3、 CPU模式切换三级跳:实模式16——>保护模式32——>长模式64 

[wit@ubuntu:src]$ cat cpu_mode_switch.asm 
; mode_switch.asm
; CPU模式三级跳:16位实模式 → 32位保护模式 → 64位长模式
; 编译:nasm -f bin -o mode_switch.bin mode_switch.asm

[BITS 16]               ; 起步:16位实模式
[ORG 0x7C00]            ; BIOS加载到0x7C00

;------------------------ 第一阶段:实模式准备 ------------------------
start:
    cli                 ; 关中断,切换过程中不能被打扰
    mov ax, 0x0000
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00      ; 设置实模式栈

    ; 1. 启用A20地址线(解锁1MB以上内存)
    in al, 0x92
    or al, 2
    out 0x92, al

    ; 2. 加载GDT
    lgdt [GDT_desc]

    ; 3. 置CR0的PE位,进入保护模式
    mov eax, cr0
    or al, 1
    mov cr0, eax

    ; 4. 远跳转刷新指令流水线,正式进入32位保护模式
    jmp dword 0x08:start_protected


;------------------------ GDT:全局描述符表 ------------------------
; 必须同时包含32位和64位的代码段/数据段描述符
align 8
GDT_start:

; 空描述符
GDT_null:       dq 0x0000000000000000

; 32位代码段 (选择子 0x08)
GDT_code32:     dw 0xFFFF       ; 段限长[15:0]
                dw 0x0000       ; 基址[15:0]
                db 0x00         ; 基址[23:16]
                db 10011010b    ; P=1 DPL=00 S=1 TYPE=1010(可执行可读)
                db 11001111b    ; G=1 D=1(32位) 限长[19:16]
                db 0x00         ; 基址[31:24]

; 32位数据段 (选择子 0x10)
GDT_data32:     dw 0xFFFF
                dw 0x0000
                db 0x00
                db 10010010b    ; TYPE=0010(可读写)
                db 11001111b
                db 0x00

; 64位代码段 (选择子 0x18) - 长模式专用
GDT_code64:     dw 0xFFFF
                dw 0x0000
                db 0x00
                db 10011010b
                db 10101111b    ; L=1(64位) D=0
                db 0x00

; 64位数据段 (选择子 0x20)
GDT_data64:     dw 0xFFFF
                dw 0x0000
                db 0x00
                db 10010010b
                db 10101111b    ; L=1 D=0
                db 0x00

GDT_end:

GDT_desc:       dw GDT_end - GDT_start - 1
                dd GDT_start


;------------------------ 第二阶段:32位保护模式 ------------------------
[BITS 32]
start_protected:
    ; 更新段寄存器
    mov ax, 0x10        ; 32位数据段选择子
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x90000    ; 设置32位栈顶

    ; 保护模式下可以做一些初始化工作
    ; 比如打印一条消息确认已进入保护模式
    ; (这里省略具体打印,我们直接准备跳长模式)

    ; --- 准备进入长模式 ---
    ; 1. 设置PAE和长模式使能位
    mov eax, 10100000b   ; PAE | PGE
    mov cr4, eax

    ; 2. 加载页表(至少需要4级页表)
    mov eax, pml4_table
    mov cr3, eax

    ; 3. 设置EFER.LME(长模式使能)
    mov ecx, 0xC0000080  ; EFER MSR
    rdmsr
    or eax, 0x00000100   ; 置LME位(第8位)
    wrmsr

    ; 4. 开启分页,这也同时正式激活长模式
    mov eax, cr0
    or eax, 0x80000000   ; 置PG位
    mov cr0, eax

    ; 5. 远跳转到64位代码段,刷新流水线
    jmp 0x18:start_long


;------------------------ 简易4级页表 ------------------------
; 恒等映射最低2MB(虚拟地址=物理地址)
align 4096
pml4_table:     dq pdp_table + 0x3   ; Present + ReadWrite
        times 511 dq 0
pdp_table:      dq pd_table + 0x3
        times 511 dq 0
pd_table:       dq 0x83 | (0x200000 * 0)  ; 2MB大页,第0个2MB
        times 511 dq 0


;------------------------ 第三阶段:64位长模式 ------------------------
[BITS 64]
start_long:
    ; 更新段寄存器(64位下大部分段基址被忽略)
    mov ax, 0x20        ; 64位数据段选择子
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov rsp, 0x100000   ; 设置64位栈顶

    ; ===== 长模式代码开始 =====
    ; 这里写你的64位逻辑
    ; 你可以验证:访问64位寄存器、使用R8-R15、处理64位地址

    ; 示例:在屏幕左上角打印一个绿色字母 'O' 确认成功
    mov rax, 0x00000000000F4F00  ; 字符'O' + 绿色背景
    mov rdi, 0xB8000             ; VGA文本模式显存基址
    mov [rdi], rax

    ; 停机
    hlt_loop:
    hlt
    jmp hlt_loop


;------------------------ 填充和魔数 ------------------------
times 510 - ($ - $$) db 0
dw 0xAA55              ; 启动扇区签名

 

 

 

三、参考资料

 

  1、  baidu  --  chat.baidu.com

.

 

posted on 2026-05-22 14:04  lnlidawei  阅读(17)  评论(0)    收藏  举报