要求
1、进入32保护模式
2、在32保护模式下,对字符串进行按照字符大小进行排序
效果
第一行:成功进入保护模式
第二行:原字符串顺序
第三行:排序后字符串顺序
代码
;-------------------------------------------------------------------------------
;设置堆栈段和栈指针
mov ax,0x7a00
mov ss,ax
mov sp,0x0200
;-------------------------------------------------------------------------------
;gdt线性地址计算
mov dx,[cs:pgdt+0x7c04]
mov ax,[cs:pgdt+0x7c02]
mov bx,0x10
div bx ;ax存商,dx存余
mov ds,ax ;段地址
mov bx,dx ;偏移地址
;-------------------------------------------------------------------------------
;#0 段描述符,空描述符,处理器要求
mov dword [bx],0x00000000
mov dword [bx+0x04],0x00000000
add bx,0x08
;#1 数据段描述符
mov dword [bx],0x0000ffff ;基地址为0,段界限0xfffff
mov dword [bx+0x04],0x00cf9200 ;粒度4KB,整个4GB空间
add bx,0x08
;#2 代码段描述符
mov dword [bx],0x7c0001ff ;基地址为0x00007c00,512字节
mov dword [bx+0x04],0x00409800 ;粒度为1个字节
add bx,0x08
;#3 代码段的别名描述符
mov dword [bx],0x7c0001ff ;基地址为0x00007c00,512字节
mov dword [bx+0x04],0x00409200 ;粒度为1个字节,用于读写代码段
add bx,0x08
;#4 栈段描述符
mov dword [bx],0x7c00fffe ;基地址为0x00007c00,段界限0xffffe
mov dword [bx+0x04],0x00cf9600 ;粒度4KB,向下扩展,4096字节
;gdtr初始化
mov word [cs:pgdt+0x7c00],39 ;gdt界限
lgdt [cs:pgdt+0x7c00]
;-------------------------------------------------------------------------------
;准备开启32保护
in al,0x92 ;南桥芯片端口
or al,0000_0010B
out 0x92,al ;A20地址线开启
cli ;关中断(尚未建立中断向量表)
mov eax,cr0
or eax,0x01
mov cr0,eax ;PE位设置,32保护开启
;进入保护模式
jmp dword 0x0010:flush ;0x0010=00000000000_10_000B
[bits 32]
;-------------------------------------------------------------------------------
flush:
;代码段别名段设置
mov eax,00000000000_11_000B
mov ds,eax
;数据段设置
mov eax,00000000000_01_000B
mov es,eax
;栈段设置
mov eax,0000000000_100_000B
mov ss,eax
mov esp,0x0
;字符打印
mov dword [es:0x0b8000],0x072e0750 ;字符'P'、'.'及其显示属性
mov dword [es:0x0b8004],0x072e074d ;字符'M'、'.'及其显示属性
mov dword [es:0x0b8008],0x07200720 ;两个空白字符及其显示属性
mov dword [es:0x0b800c],0x076b076f ;字符'o'、'k'及其显示属性
;-------------------------------------------------------------------------------
;排序前字符显示
mov ecx,pgdt-string ;字符串长度
xor ebx,ebx ;遍历字符串
@0:
mov ah,0x07
mov al,[ebx+string]
mov [es:0xb80a0+2*ebx],ax ;写入显存
inc ebx
loop @0
;-------------------------------------------------------------------------------
;冒泡排序
mov ecx,pgdt-string-1 ;外层循环
@1:
push ecx ;压入外层循环ecx
xor bx,bx ;遍历字符串
@2: ;内层循环
mov ax,[bx+string] ;获取两个字符
cmp ah,al
jge @3 ;若前一个字符(al)<后一个字符(ah)则跳转
xchg ah,al ;交换ah,al
mov [bx+string],ax ;填回交换后的ah,al
@3:
inc bx ;向前推进一位
loop @2
pop ecx ;返回外层循环
loop @1
;-------------------------------------------------------------------------------
;排序后字符显示
mov ecx,pgdt-string ;字符串长度
xor ebx,ebx ;遍历字符串
@4:
mov ah,0x07
mov al,[ebx+string]
mov [es:0xb8140+2*ebx],ax ;写入显存
inc ebx
loop @4
;-------------------------------------------------------------------------------
;停机指令
hlt
;-------------------------------------------------------------------------------
string db 's0ke4or92xap3fv8giuzjcy5l1m7hd6bnqtw.'
;-------------------------------------------------------------------------------
pgdt dw 0
dd 0x00007e00 ;GDT的物理地址
;-------------------------------------------------------------------------------
times 510-($-$$)db 0
db 0x55,0xaa