1 ;16位代码
2 [bits 16]
3 ;初始化实模式下的数据段,代码段,堆栈段
4 mov eax, cs
5 mov ss, eax
6 mov sp, 0x7C00 ;实模式下的栈在引导扇区的下边
7 ;将保护模式下的线性地址转换为实模式下的段地址:偏移地址的形式
8 xor edx, edx ;此处使用64位除法, 高32位清零
9 mov eax, [cs:gdt_base + 0x7C00] ;使用超越段前缀访问数据
10 mov ebx,16 ;线性地址 = 段地址 X 16 + 偏移地址
11 div ebx
12 ;设置指向描述符的数据段
13 mov ebx, edx ;余数为偏移地址
14 mov ds, eax
15 ;安装数据段描述符
16 ;#0空描述符
17 mov dword [ebx + 0x00], 0x0000_0000
18 mov dword [ebx + 0x04], 0x0000_0000
19 ;#1代码段
20 mov dword [ebx + 0x08], 0x7C00_01FF
21 mov dword [ebx + 0x0C], 0x0040_9800
22 ;#2数据段
23 mov dword [ebx + 0x10], 0x0000_FFFF
24 mov dword [ebx + 0x14], 0x00CF_9200
25 ;#3别名代码段
26 mov dword [ebx + 0x18], 0x7C00_01FF
27 mov dword [ebx + 0x1C], 0x0040_9200
28 ;#4堆栈段
29 mov dword [ebx + 0x20], 0x0000_6BFF
30 mov dword [ebx + 0x24], 0x0040_9600
31 ;加载GDT
32 mov word [cs:gdt_size + 0x7C00], 0x27
33 lgdt [cs:gdt_size + 0x7C00]
34 ;打开A20
35 in al, 0x92
36 or al, 0000_0010B
37 out 0x92, al
38 ;关中断
39 cli
40 ;进入保护模式(16位)
41 mov eax, cr0
42 or eax, 0000_0001B
43 mov cr0, eax
44 ;进入保护模式(32位)
45 jmp dword 0x08:flush
46 ;32位代码
47 [bits 32]
48 flush:
49 ;加载别名代码段
50 mov eax, 0x18
51 mov ds, eax
52
53 ;加载数据段
54 mov eax, 0x10
55 mov es, eax
56
57 ;加载堆栈
58 mov eax, 0x20
59 mov ss, eax
60 mov esp, 0x0000_7BFF
61
62 ;在屏幕上启动信息字符
63 mov ecx, gdt_size - welcome
64 xor ebx, ebx
65 wel:
66 mov al, [ebx + welcome]
67 mov ah, 0x0A
68 mov [es:0x000B_8000 + ebx * 2], ax
69 inc ebx
70 loop wel
71 ;冒泡排序
72 mov ecx, welcome - string - 1
73 external:
74 xor ebx, ebx
75 push ecx
76 internal:
77 mov ax, [ebx + string]
78 cmp ah, al
79 jg con
80 xchg ah, al
81 mov word [ebx + string], ax
82 con:
83 inc ebx
84 loop internal
85 pop ecx
86 loop external
87 ;显示排序的结果
88 mov ecx, welcome - string
89 xor ebx, ebx
90 res:
91 mov al, [ebx + string]
92 mov ah, 0x0A
93 mov [es:0x000B_8000 + 160 + ebx * 2], ax
94 inc ebx
95 loop res
96 ;停机
97 hlt
98 ;要进行排序的串
99 string: db '958458456541186545552135789642589103598416552556'
100 welcome: db 'Welcome to Lixiaomao boot.'
101 ;GDT位置和界限
102 gdt_size: dw 0 ;这个字用于存放GDT的界限
103 gdt_base: dd 0x0000_7E00 ;打算将GDT放在引导扇区的后边
104 ;填充剩余扇区
105 times 510 - ($ - $$) db 0
106 db 0x55, 0xAA