; Module servant a passer en 32 bits et a executer la fonction ; dont l'adresse est passee en parametre et a revenir en mode 16 bits ; pour tester => adresse 16 bits ; Auteur: Benoit Papillault ; Creation: 10 Juin 1997 ; Derniere modification: Dimanche 29 Juin 1997 ; Historique: ; 25/06/1997: ajout de code dans demo_int afin de comprendre l'etat de la ; pile lors d'une interruption include model.inc include selector.inc include print16.inc include print32.inc .386p MEM_VIDEO equ 0b800h ATTRIBUTS equ 0a0h io_range equ 2000h segment_descriptor struc segment_limit15_0 dw ? ; low word of the segment length segment_base15_0 dw ? ; low word of base address segment_base23_16 db ? ; low byte of high word of base addr. segment_flags db ? ; segment type and misc. flags segment_limit19_16 db ? ; highest nibble of segment length ; and access flags segment_base31_24 db ? ; highest byte of base address segment_descriptor ends gate_descriptor struc gate_offset15_0 dw ? ; low word of handler offset gate_selector dw ? ; segment selector gate_param_count db 0 ; unused in this descriptor format gate_flags db ? ; flag-byte gate_offset31_16 dw ? ; high-word of handler offset gate_descriptor ends fcode segment public use32 at 0 org 0 fcode ends fdata segment public use32 at 0 org 0 fdata ends _DATA segment word public 'DATA' gdt label byte dummy_descriptor segment_descriptor <0,0,0,0,0,0> code16_descriptor segment_descriptor <0ffffh,0,0,9ah,0,0> ; 64k 16-bit code code32_descriptor segment_descriptor <0ffffh,0,0,9ah,0cfh,0> ; 4GB 32-bit code data16_descriptor segment_descriptor <0ffffh,0,0,92h,0,0> ; 64k 16-bit data data32_descriptor segment_descriptor <0ffffh,0,0,92h,0cfh,0> ; 4GB 32-bit data fdata_descriptor segment_descriptor <0ffffh,0,0,92h,0cfh,0> ; 4GB 32-bit core data fcode_descriptor segment_descriptor <0ffffh,0,0,9ah,0cfh,0> ; 4GB 32-bit core code stack32_descriptor segment_descriptor <0ffffh,0,0,92h,0cfh,0>; expand down stack tss_descriptor segment_descriptor <68h+io_range,0,0,89h,0,0> gdt_size=$-gdt public fdata_sel,data32_sel ; la definition des selecteurs dummy_sel equ dummy_descriptor - gdt code16_sel equ code16_descriptor - gdt code32_sel equ code32_descriptor - gdt data16_sel equ data16_descriptor - gdt data32_sel equ data32_descriptor - gdt fdata_sel equ fdata_descriptor - gdt fcode_sel equ fcode_descriptor - gdt stack32_sel equ stack32_descriptor - gdt tss_sel equ tss_descriptor - gdt interrupt_0 gate_descriptor ;00 gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor gate_descriptor idt_size=$-(offset interrupt_0) notre_gdt dw gdt_size gdt_base dd ? dw 0 notre_idt dw idt_size idt_base dd ? dw 0 idt_real df 3ffh ; Real Mode IDT dw 0 le_tss db io_range+69h dup (0) real_ss dw ? real_sp dw ? adr_exec dd ? ; l'adresse de la fonction a excuter dans fcode dw fcode_sel adr_test dd offset code32:fonction_test dw code32_sel adr_test2 dd ? ; offset fcode:fonction_test => FIXUPs OverFlow dw fcode_sel adr_saut dd ? dw fcode_sel demo_mess db 'In protected mode interrupt 0',0 msg_esp db 'esp=0x',0 msg_p_ebp db '[ebp]=0x',0 msg_p_ebp_4 db '[ebp+4]=0x',0 msg_p_ebp_8 db '[ebp+8]=0x',0 msg_p_ebp_12 db '[ebp+12]=0x',0 msg_p_ebp_16 db '[ebp+16]=0x',0 msg_adr_exec db 'adr_exec=0x',0 msg_offset db 'offset=0x',0 msg_intno db 'interruption=0x',0 ; on reserve un peu de memoire pour la pile (ici 4Ko) db 4096 dup (0) stack16 label byte _DATA ends code32 segment para public use32 assume cs:code32 main32: ; chargment de tous les segments mov ax,data32_sel mov ds,ax mov es,ax mov fs,ax mov gs,ax ; creation de la pile mov ax,stack32_sel mov ss,ax mov esp,offset stack16 mov eax,0c1c2c3c4h push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax push eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax pop eax call test_asm32 call _print_al32 call _print_ax32 call _print_eax32 call crlf32 assume ds:_DATA mov eax,offset msg_adr_exec push eax call _print_st32 pop eax mov eax,adr_exec call _print_eax32 call crlf32 ; call [adr_exec] ; ne convient pas car adr_exec est dans le segment fcode xor eax,eax mov ax,code32 shl eax,4 add eax,offset suite1 mov adr_saut,eax jmp fword ptr [adr_saut] suite1: ; ici CS=fcode_sel donc on peut faire call [adr_exec] ; mais au prealable on doit avoir DS=fdata_sel (peut-etre aussi pour les ; autres registres de segment ES,FS,GS) mov ebx,[adr_exec] mov ax,fdata_sel mov ds,ax xor eax,eax call ebx mov bx,data32_sel mov ds,bx call _print_eax32 call crlf32 ; call fword ptr [adr_test] xor eax,eax mov ax,code32 shl eax,4 add eax,offset fonction_test mov adr_test2,eax ;test call fword ptr [adr_test2] suite32: mov eax,089abcdefh ; pour avoir un motif dans la pile push eax ;test int 0h pop eax ; retour au mode 16 bits db 0eah dw offset retour16,0,code16_sel ; fin du code de main32 fonction_test: push ebp mov ebp,esp mov eax,01234567h ; pour avoir un motif dans la pile push eax int 0h pop eax pop ebp retf ; eh eh ... call fword => changement de segments demo_int: push ebp mov ebp,esp push eax push ebx mov eax,offset demo_mess push eax call _print_st32 pop eax call crlf32 mov eax,offset msg_esp push eax call _print_st32 pop eax mov eax,esp call _print_eax32 call crlf32 mov eax,offset msg_p_ebp push eax call _print_st32 pop eax mov eax,[ebp] call _print_eax32 call crlf32 mov eax,offset msg_p_ebp_4 push eax call _print_st32 pop eax mov eax,[ebp+4] call _print_eax32 call crlf32 mov eax,offset msg_p_ebp_8 push eax call _print_st32 pop eax mov eax,[ebp+8] call _print_eax32 call crlf32 mov eax,offset msg_p_ebp_12 push eax call _print_st32 pop eax mov eax,[ebp+12] call _print_eax32 call crlf32 mov eax,offset msg_p_ebp_16 push eax call _print_st32 pop eax mov eax,[ebp+16] call _print_eax32 call crlf32 pop ebx pop eax pop ebp iretd ; a completer exc_1: push eax mov al,1 jmp exc_general exc_2: push eax mov al,2 jmp exc_general exc_3: push eax mov al,3 jmp exc_general exc_4: push eax mov al,4 jmp exc_general exc_5: push eax mov al,5 jmp exc_general exc_6: push eax mov al,6 jmp exc_general exc_7: push eax mov al,7 jmp exc_general exc_8: push eax mov al,8 jmp exc_general exc_9: push eax mov al,9 jmp exc_general exc_10: push eax mov al,10 jmp exc_general exc_11: push eax mov al,11 jmp exc_general exc_12: push eax mov al,12 jmp exc_general exc_13: push eax mov al,13 jmp exc_general exc_14: push eax mov al,14 jmp exc_general exc_15: push eax mov al,15 jmp exc_general exc_16: push eax mov al,16 jmp exc_general exc_17: push eax mov al,17 jmp exc_general exc_general: ; on prealable, on fait: ; push eax ; mov al,intno push ebx mov ebx,offset msg_intno push ebx call _print_st32 pop ebx call _print_al32 call crlf32 pop ebx pop eax iretd code32 ends _TEXT segment public use16 'CODE' assume cs:_TEXT public init_tss init_tss proc PROC_MODEL assume ds:_DATA ; code d'entree d'une fonction C push bp mov bp,sp ; sauvegarde des registres utilises push cx push es push di ; note: stosb est equivalent a mov [es:di],al mov cx,io_range+69h mov ax,_DATA mov es,ax mov di,offset le_tss cld xor al,al rep stosb mov byte ptr le_tss[io_range+68h],-1 mov word ptr le_tss[66h],68h ; restauration des registres pop di pop es pop cx ; code de sortie d'une fonction C pop bp ret assume ds:nothing init_tss endp public _exec32 ; void exec32(void (*f)()) ; avant d'appeler cette fonction, il faut s'assurer que le processeur ; est au moins un 386, et que l'on n'est pas deja en mode v86 _exec32 proc PROC_MODEL ; code d'entree d'une fonction C push bp mov bp,sp ; on sauvegarde les registres push eax push ebx push di push ds push es push fs push gs ; debut du code mov ax,_DATA mov ds,ax assume ds:_DATA ; sauvegarde de la pile mov ax,ss mov real_ss,ax mov real_sp,sp ; quelques tests call _test_asm16 ; on recupere l'adresse lineaire de la fonction a executer mov eax,[bp+cPtrSize+2] mov adr_exec,eax ; le segment de code 32 bits -> code32 xor eax,eax mov ax,code32 shl eax,4 mov code32_descriptor.segment_base15_0,ax shr eax,16 mov code32_descriptor.segment_base23_16,al ; le segment de donnees 16/32 bits + la pile mov ax,_DATA movzx eax,ax shl eax,4 mov data32_descriptor.segment_base15_0,ax mov data16_descriptor.segment_base15_0,ax mov stack32_descriptor.segment_base15_0,ax shr eax,16 mov data32_descriptor.segment_base23_16,al mov data16_descriptor.segment_base23_16,al mov stack32_descriptor.segment_base23_16,al ; le tss call init_tss xor eax,eax mov ax,_DATA shl eax,4 xor ebx,ebx mov bx,offset le_tss add eax,ebx mov tss_descriptor.segment_base15_0,ax shr eax,16 mov tss_descriptor.segment_base23_16,al ; le segment de code 16 bits xor eax,eax mov ax,_TEXT shl eax,4 mov code16_descriptor.segment_base15_0,ax shr eax,16 mov code16_descriptor.segment_base23_16,al ; chargement de la gdt xor eax,eax mov ax,_DATA shl eax,4 xor ebx,ebx mov bx,offset dummy_descriptor add eax,ebx mov gdt_base,eax ; initialisation de la idt ; interruption 0 mov di,offset interrupt_0 mov eax,offset demo_int mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 1 add di,size gate_descriptor mov eax,offset exc_1 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 2 add di,size gate_descriptor mov eax,offset exc_2 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 3 add di,size gate_descriptor mov eax,offset exc_3 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 4 add di,size gate_descriptor mov eax,offset exc_4 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 5 add di,size gate_descriptor mov eax,offset exc_5 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 6 add di,size gate_descriptor mov eax,offset exc_6 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 7 add di,size gate_descriptor mov eax,offset exc_7 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 8 add di,size gate_descriptor mov eax,offset exc_8 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 9 add di,size gate_descriptor mov eax,offset exc_9 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 10 add di,size gate_descriptor mov eax,offset exc_10 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 11 add di,size gate_descriptor mov eax,offset exc_11 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 12 add di,size gate_descriptor mov eax,offset exc_12 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 13 add di,size gate_descriptor mov eax,offset exc_13 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 14 add di,size gate_descriptor mov eax,offset exc_14 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 15 add di,size gate_descriptor mov eax,offset exc_15 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 16 add di,size gate_descriptor mov eax,offset exc_16 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; interruption 17 add di,size gate_descriptor mov eax,offset exc_17 mov [di].gate_offset15_0,ax shr eax,16 mov [di].gate_offset31_16,ax ; chargement de la idt xor eax,eax mov ax,_DATA shl eax,4 mov ebx,offset interrupt_0 add eax,ebx mov idt_base,eax ; jmp short fin_exec32 ; bientot le mode 32 bits lgdt fword ptr [notre_gdt] lidt fword ptr [notre_idt] mov eax,cr0 or al,1 mov cr0,eax ; on definit le registre de tache mov ax,tss_sel ltr ax ; far jump (to load new CS) db 0eah dw offset main32 dw code32_sel retour16: ; on charge les registres de segments avec des valeurs acceptables pour le ; mode reel (on est encore en mode protege 16 bits) mov ax,data16_sel mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax ; chargement de la idt pour le mode reel lidt idt_real ; on revient en mode reel (a regarder plus en detail) mov eax,10h mov cr0,eax xor eax,eax mov cr3,eax db 0eah dw offset flush_ipq,_TEXT flush_ipq: ; charger les registres de segments avec leur valeur en mode reel mov ax,_DATA mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax mov esp,offset stack16 ; on restaure la pile fin_exec32: assume ds:_DATA mov ax,real_ss mov ss,ax mov sp,real_sp pop gs pop fs pop es pop ds pop di pop ebx pop eax mov ax,1 sti ; code de retour d'une fonction C pop bp ret _exec32 endp ;----------------------------------------------------------------------------- testA20 proc PROC_MODEL ; Test for enabled A20 mov al,fs:[0] mov ah,al not al mov gs:[10h],al cmp ah,fs:[0] mov fs:[0],ah ret testA20 endp ;---------------------------------------------------------------------------- enableA20 proc PROC_MODEL ; hardware enable gate A20 xor ax,ax mov fs,ax dec ax mov gs,ax call testA20 je short enableA20done in al,92h ; PS/2 A20 enable or al,2 jmp short $+2 jmp short $+2 jmp short $+2 out 92h,al call testA20 je short enableA20done call enableA20o1 ; AT A20 enable jnz short enableA20wait mov al,0d1h out 64h,al call enableA20o1 jnz short enableA20wait mov al,0dfh out 60h,al push offset enableA20wait ; ???? enableA20o1: mov ecx,20000h enableA20o1l: jmp short $+2 jmp short $+2 jmp short $+2 in al,64h test al,2 loopnz enableA20o1l enableA20done: ret enableA20 endp ;----------------------------------------------------------------------------- enableA20wait proc PROC_MODEL ; wait for A20 mov al,36h out 43h,al xor al,al out 40h,al out 40h,al mov cx,800h enableA20waitl0: call testA20 je enableA20done in al,40h in al,40h mov ah,al enableA20waitl1: in al,40h in al,40h cmp al,ah je enableA20waitl1 loop enableA20waitl0 ; mov dx,offset errmsg4 ; jmp exit16err enableA20wait endp _TEXT ends end