一开始使用C编写进入PM代码,因为内嵌汇编太多,不易查询汇编如何出错,所以改用纯汇编编写。
过程中学到一个小技巧,当赋值的数太大时,编译会报错,这时在数前加个0即可解决。
程序编译完成,基本过程已然了解,但是在测试机上跑的时候会自动重启。
;;;;;;;;;;;;;;;;;;;程序开始;;;;;;;;;;;;;;;;;; ;data struct jump macro selector, offset db 0eah dw offset dw selector endm desp struc segLimit dw 0; byte0, 1 segBaseLow dw 0; byte2, 3 segBaseMid db 0; byte4 segAttribute dw 0; byte5, 6 segBaseHigh db 0; byte7 desp ends pgdt struc segLimit dw 0ffffh; byte 0, 1 segBase dd 0; byte 2, 3, 4, 5 pgdt ends ;------------------------------------------------------------- ------- ; real mode data segment begin ;.data .386p; if not p, lgdt is not defined dseg segment use16 ; gdt segment begin gdt label byte DUMMY desp <>; 空描述符!!! dataSegDesp desp <0ffffh,0h,0h,092h,> ; data segment is started with: 0x00000000h dataSegSel = dataSegDesp - gdt codeSegDesp desp <0ffffh,,,098h,> codeSegSel = codeSegDesp - gdt extSegDesp desp <0ffffh,,88h,092h,> ; ext segment is started with: 0x00880000h extSegSel = extSegDesp - gdt gdtLen = $ - gdt pgdtr pgdt; gdt segment end ; pmode data segment begin buffers db 256 dup('@') bufferLen = $ - offset buffers msgLen = $ - offset msg ; pmode data segment end bufferd db 256 dup('y') bufferd2 db 256 dup('x') dseg ends ; real mode data segment end ;------------------------------------------------------------- ------- cseg segment use16 ;.code assume cs:cseg, ds:dseg start: MOV ax, dseg MOV ds, ax ;prepare to jump to pmode ;1>. init gdtr ;2>. init code descriptor ;3>. init data descriptor ;4>. enable a20 address ;5>. set cr0 ;6>. jump pmode ;1>. init gdtr MOV bx, 16 MUL bx ADD ax, offset gdt ADC dx, 0 MOV WORD PTR pgdtr.segBase, ax MOV WORD PTR pgdtr.segBase+2, dx ;2>. init code descriptor MOV ax, cs MUL bx MOV codeSegDesp.segBaseLow, ax MOV codeSegDesp.segBaseMid, dl MOV codeSegDesp.segBaseHigh, dh ;3>. init data descriptor MOV ax, ds MUL bx ADD ax, offset buffers adc dx, 0 MOV dataSegDesp.segBaseLow, ax MOV dataSegDesp.segBaseMid, dl MOV dataSegDesp.segBaseHigh, dh lgdt pgdtr ;4>. enable A20 address cli ;call enableA20 PUSH ax in al, 92h or al, 2 out 92h, al POP ax ;5>. set cr0 MOV eax, cr0 or eax, 1 MOV cr0, eax ;6>. jump to pmode ;JMP pmode jump , pmode: MOV ax, dataSegSel MOV ds, ax MOV ax, extSegSel MOV es, ax ;;;;;;;访问SPI空间的内容;;;;;;;;; mov ebx,[0fed1f800h] mov ds:[0000],ebx mov dx,0 mov ah,9 int 21h ;;;;;;;;;;;;;;;; MOV eax, cr0 and eax, 0fffffffeh MOV cr0, eax JMP rmode rmode: call disableA20 sti MOV ax, dseg MOV ds, ax disableA20 proc PUSH ax in al, 92h and al, 0fdh out 92h, al POP ax RET disableA20 endp MOV ah, 4ch int 21h cseg ends END start