Page 1 of 1

Print character into protected mode with TASM 16 bits

Posted: Tue Nov 13, 2007 2:43 am
by Lovmy
Hello,

I has modified code in http://charles.moostik.net/pmode/ind...?page=Exemple1
to print char in real and protected mode.

Complete code is:

Code: Select all

P386

Descripteur_Segment STRUC
  Limite        dw      ?
  Base_0_15     dw      ?
  Base_16_23    db      ?
  Flags_1       db      ?
  Flags_2       db      ?  
  Base_24_31    db      ?
Descripteur_Segment ENDS


Donnees SEGMENT USE16
 
  GDT   DW      GDT_Size
  DD      offset Descripteur_Nul
  
  toto	DW	0
  V86	DB	"Le processeur est en mode V86.",10,13,"$"  
  Good	DB      	"Ca a marche !!!",10,13,"$"

  Descripteur_Nul		Descripteur_Segment <0, 0, 0, 0, 0, 0>
  code_16_desc		Descripteur_Segment <0FFFFh, 0, 0, 9Ah, 0, 0>
  Donnees_16_desc		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>
  Pile_16_desc		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>

  GDT_Size       EQU    $ - Offset Descripteur_Nul

  Code_16_idx	EQU	08h
  Donnees_16_idx	EQU	10h
  Pile_16_idx	EQU	18h

Donnees ENDS

Pile 	SEGMENT STACK USE16
 	 DB	512	DUP (?)
Pile 	ENDS

Mon_Code SEGMENT USE16

    ASSUME CS:Mon_Code, DS:Donnees

Debut :

  MOV	AX, Donnees
  MOV	DS,	AX	

  MOV AX, 0003h					; Mode texte
  INT 10h
  
  MOV BX, 0B800h
  MOV ES, BX
  MOV DI, 0
  MOV byte ptr ES:[DI], 'A'
  INC DI
  MOV byte ptr ES:[DI], 02h

  MOV	EAX,	CR0
  TEST	AL,	1	
  JZ    Ok
; Teste si on se trouve en mode V86

  MOV	DX,	OFFSET V86  
  MOV	AH,	09h
  INT	21h	
  JMP   Fin
; On affiche un message et on quite : V86

Ok:
  MOV	EAX, 	Mon_Code
  SHL	EAX,	4
  MOV	Code_16_Desc.Base_0_15,	AX
  SHR	EAX,	16
  MOV	Code_16_Desc.Base_16_23, AL
  MOV   Code_16_Desc.Base_24_31, AH
; Met à jour le selecteur du segment de Code.


  MOV	EAX, 	Donnees
  SHL	EAX,	4
  MOV	Donnees_16_Desc.Base_0_15, AX
  SHR	EAX,	16
  MOV	Donnees_16_Desc.Base_16_23, AL
  MOV   Donnees_16_Desc.Base_24_31, AH
; Met … jour le selecteur du segment de Données.


  MOV	EAX, 	Pile
  SHL	EAX,	4
  MOV	Pile_16_Desc.Base_0_15,	AX
  SHR	EAX,	16
  MOV	Pile_16_Desc.Base_16_23, AL
  MOV   Pile_16_Desc.Base_24_31, AH
; Met … jour le selecteur du segment de Pile.

  MOV	EAX,	Donnees
  SHL	EAX,	4	
  ADD	DWORD PTR GDT[2], EAX
; Met … jour la variable GDT

  LGDT 	FWORD PTR GDT
; Charge la GDT

  MOV	EAX,	CR0
  OR	AL,	1
  MOV	CR0,	EAX
; Commute en PMode

  DB	0EAh
  DW	$+4, Code_16_idx
; Charge un selecteur dans CS...

  MOV	AX,	Donnees_16_idx
  MOV	DS,	AX
; ...dans DS

  MOV	AX,	Pile_16_idx
  MOV	SS,	AX
; ...et dans SS (la pile)

  MOV	toto,	50
; Ceci est juste un test !

	DB 0B8h ; mov eax,0xb8000
	DB 00h
	DB 80h
	DB 0Bh
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x42 (B)
	DB 00h
	DB 42h
	
	DB 0B8h ; mov eax,0xb8001
	DB 01h
	DB 80h
	DB 0Bh
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x2 (vert)
	DB 00h
	DB 02h
	
  MOV	EAX,	CR0
  AND	AL,	NOT 1
  MOV	CR0,	EAX
; Repasse en PMode

  DB	0EAh
  DW	$+4, Mon_Code

  MOV	AX, 	Donnees
  MOV	DS,	AX

  MOV	AX, 	Pile
  MOV	SS,	AX
; Recharge des segments

  CMP   toto,   50
  JNE   Fin
; On verifie si la variable … bien march‚

  ;MOV   DX,     OFFSET Good
  ;MOV   AH,     09h
  ;INT   21h

Fin:

  MOV	AX,	4C00h
  INT	21h

Mon_Code ENDS

END Debut
I have added:

Code: Select all

MOV AX, 0003h					; Mode texte
  INT 10h
  
  MOV BX, 0B800h
  MOV ES, BX
  MOV DI, 0
  MOV byte ptr ES:[DI], 'A'
  INC DI
  MOV byte ptr ES:[DI], 02h
In real mode, no problem, green A is printed at screen.
But i compile with TASM 16bits, and this compiler don't support [BITS 32] keyword. In protected mode i think i can't write assembleur code because TASM don't generate 32 bits code. I have add directly opcode into protected mode section, see:

Code: Select all

DB 0B8h ; mov eax,0xb8000
	DB 00h
	DB 80h
	DB 0Bh
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x42 (B)
	DB 00h
	DB 42h
	
	DB 0B8h ; mov eax,0xb8001
	DB 01h
	DB 80h
	DB 0Bh
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x2 (vert)
	DB 00h
	DB 02h
I don't have error (no triple fault, no reboot), but only character un real mode is printing, in protected mode B is not printing.

Can you help me ?

Thank !!!

Posted: Tue Nov 13, 2007 4:02 am
by Combuster
My french is poor, but as far as I can see the pattern looks like this
1: patch the GDT (all entries!) with the base addresses of each real mode segment
2: enter protected mode
3: load DS with a 4G segment starting at the start of the data segment
4: write to DS:0xb8000
5: exit

the error is the combination of 1 and 4: you assign a non-zero base to the DS descriptor, then you use it as if it does have a zero base. Instead you're accessing [0xb8000 + data segment location], which is probably *not* where you want to send your data to...

P.S. if you are serious about writing 32-bit code, consider using nasm

No result

Posted: Wed Nov 14, 2007 2:06 pm
by Lovmy
Hello,

I have try to add descriptor to video memory, begin to àxB8000 see:

Code: Select all

P386

Descripteur_Segment STRUC
  Limite        dw      ?
  Base_0_15     dw      ?
  Base_16_23    db      ?
  Flags_1       db      ?
  Flags_2       db      ?  
  Base_24_31    db      ?
Descripteur_Segment ENDS

Donnees SEGMENT USE16
 
  GDT   DW      	GDT_Size
  DD      			offset Descripteur_Nul
  
  toto	DW	0
  Good	DB      	"Ca a marche !!!",10,13,"$"

  Descripteur_Nul	Descripteur_Segment <0, 0, 0, 0, 0, 0>
  code_16_desc		Descripteur_Segment <0FFFFh, 0, 0, 9Ah, 0, 0>
  Donnees_16_desc	Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>
  Pile_16_desc		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>
  Video_desc		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>

  GDT_Size       	EQU    $ - Offset Descripteur_Nul

  Code_16_idx		EQU	08h
  Donnees_16_idx	EQU	10h
  Pile_16_idx		EQU	18h
  Video_idx			EQU 20h

Donnees ENDS

Pile 	SEGMENT STACK USE16
 	 DB	512	DUP (?)
Pile 	ENDS

Mon_Code SEGMENT USE16

    ASSUME CS:Mon_Code, DS:Donnees

Debut :

  MOV	AX, Donnees
  MOV	DS,	AX	

  MOV AX, 0003h					; Mode texte
  INT 10h
  
  MOV BX, 0B800h
  MOV ES, BX
  MOV DI, 0
  MOV byte ptr ES:[DI], 'A'
  INC DI
  MOV byte ptr ES:[DI], 02h						; <---------------- EAX ---------------->
												;                     <------- AX ------>
  MOV	EAX, 	Mon_Code						; 0000 0000 0000 000Y 0000 0000 0000 000X
  SHL	EAX,	4								; 0000 0000 000Y 0000 0000 0000 000X 0000
  MOV	Code_16_Desc.Base_0_15,	AX				;                     <-- AH -> <-- AL ->
  SHR	EAX,	16								; 0000 0000 0000 0000 0000 0000 000Y 0000
  MOV	Code_16_Desc.Base_16_23, AL
  MOV   Code_16_Desc.Base_24_31, AH
; Met a jour le selecteur du segment de Code.


  MOV	EAX, 	Donnees
  SHL	EAX,	4
  MOV	Donnees_16_Desc.Base_0_15, AX
  SHR	EAX,	16
  MOV	Donnees_16_Desc.Base_16_23, AL
  MOV   Donnees_16_Desc.Base_24_31, AH
; Met a jour le selecteur du segment de Données.


  MOV	EAX, 	Pile
  SHL	EAX,	4
  MOV	Pile_16_Desc.Base_0_15,	AX
  SHR	EAX,	16
  MOV	Pile_16_Desc.Base_16_23, AL
  MOV   Pile_16_Desc.Base_24_31, AH
; Met a jour le selecteur du segment de Pile.

  MOV	EAX, 	0B8000h
  MOV	Video_Desc.Base_0_15,	AX
  SHR	EAX,	16
  MOV	Video_Desc.Base_16_23, AL
  MOV   Video_Desc.Base_24_31, AH
; Met a jour le selecteur du segment de memoire video.

  MOV	EAX,	Donnees
  SHL	EAX,	4	
  ADD	DWORD PTR GDT[2], EAX
; Met a jour la variable GDT

  LGDT 	FWORD PTR GDT
; Charge la GDT

  MOV	EAX,	CR0
  OR	AL,	1
  MOV	CR0,	EAX
; Commute en PMode

  DB	0EAh
  DW	$+4, Code_16_idx
; Charge un selecteur dans CS...

  MOV	AX,	Donnees_16_idx
  MOV	DS,	AX
; ...dans DS

  MOV	AX,	Pile_16_idx
  MOV	SS,	AX
; ...et dans SS (la pile)

  MOV	toto,	50
; Ceci est juste un test !

  MOV	AX,	Video_idx
  MOV	DS,	AX
; Swap vers la memoire video

	DB 0B8h ; mov eax,0x00000
	DB 00h
	DB 00h
	DB 00h
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x42 (B)
	DB 00h
	DB 42h
	
	DB 0B8h ; mov eax,0x00001
	DB 01h
	DB 00h
	DB 00h
	DB 00h
	
	DB 0C6h ; mov byte [eax],0x2 (vert)
	DB 00h
	DB 02h

  MOV	AX,	Donnees_16_idx
  MOV	DS,	AX
; swap vers le segment de donnee
	
  MOV	EAX,	CR0
  AND	AL,	NOT 1
  MOV	CR0,	EAX
; Repasse en PMode

  DB	0EAh
  DW	$+4, Mon_Code

  MOV	AX, 	Donnees
  MOV	DS,	AX

  MOV	AX, 	Pile
  MOV	SS,	AX
; Recharge des segments

  CMP   toto,   50
  JNE   Fin
; On verifie si la variable … bien march‚

  ;MOV   DX,     OFFSET Good
  ;MOV   AH,     09h
  ;INT   21h

Fin:

  MOV	AX,	4C00h
  INT	21h

Mon_Code ENDS

END Debut
But no char is print, same if i dont set start adress to 0xB8000 but at 0 and print to adress 0xB8000.

I don't understand where is my error.
Can you help me ?

Thank

Posted: Thu Nov 15, 2007 2:55 am
by Combuster
you coded (near MOV AX, Donnees_16_idx)

Code: Select all

00000000  B81000            mov ax,0x10  
00000003  8ED8              mov ds,ax
which the processor interpreted as

Code: Select all

00000000  B810008ED8        mov eax,0xd88e0010
again, you should _really_ use a 32 bit capable assembler.
www.google.com/search?q=nasm
www.google.com/search?q=yasm

rewrite code

Posted: Thu Nov 15, 2007 1:49 pm
by Lovmy
I have rewrite code with 2 segments, on compiled in 16 bits and another in 32, see:

Code: Select all

.386P

Descripteur_Segment STRUC
	Limite        dw      ?
	Base_0_15     dw      ?
	Base_16_23    db      ?
	Flags_1       db      ?
	Flags_2       db      ?  
	Base_24_31    db      ?
Descripteur_Segment ENDS

Segment_debut	EQU 00h		;	07E0h
Index_Code		EQU	08h
Index_Donnees	EQU	10h
Index_Pile		EQU	18h
Index_Video		EQU 20h

CODE_16 SEGMENT byte USE16 public 'CODE'

	ASSUME CS:CODE_16, DS:DATA_16, SS:PILE
	
debut:
    CLD
    CLI											; Pas d'interruption
    
    MOV	AX, DATA_16								; charge DS avec le segment de donnees
    ADD AX, Segment_debut						; reference en mode boot
    MOV	DS,	AX
    
    MOV AX, 0003h								; Mode texte
    INT 10h
    
    MOV BX, 0B800h								; Affiche un A vert
    MOV ES, BX
    MOV DI, 0
    MOV BYTE PTR ES:[DI], 'A'
    INC DI
    MOV BYTE PTR ES:[DI], 02h

        MOV	EAX, CODE_32
        ADD EAX, Segment_debut
	SHL	EAX, 4
	MOV	Descripteur_Code.Base_0_15,	AX
	SHR	EAX, 16
	MOV	Descripteur_Code.Base_16_23, AL
	MOV Descripteur_Code.Base_24_31, AH
	; Met a jour le selecteur du segment de Code.
	
	MOV	EAX, DATA_32
	ADD EAX, Segment_debut
	SHL	EAX, 4
	MOV	Descripteur_Donnees.Base_0_15, AX
	SHR	EAX, 16
	MOV	Descripteur_Donnees.Base_16_23, AL
	MOV Descripteur_Donnees.Base_24_31, AH
	; Met a jour le selecteur du segment de Données.
	
	MOV	EAX, PILE
	ADD EAX, Segment_debut
	SHL	EAX, 4
	MOV	Descripteur_Pile.Base_0_15,	AX
	SHR	EAX, 16
	MOV	Descripteur_Pile.Base_16_23, AL
	MOV Descripteur_Pile.Base_24_31, AH
	; Met a jour le selecteur du segment de Pile.
	
	MOV	EAX, 0B8000h
	MOV	Descripteur_Video.Base_0_15, AX
	SHR	EAX, 16
	MOV	Descripteur_Video.Base_16_23, AL
	MOV Descripteur_Video.Base_24_31, AH
	; Met a jour le selecteur du segment de memoire video.
	
	MOV	EAX, DATA_16
	ADD EAX, Segment_debut
	SHL	EAX, 4
	ADD	DWORD PTR GDT[2], EAX
	; Met a jour la variable GDT
	
	LGDT FWORD PTR GDT
	; Charge la GDT
	
	MOV	EAX, CR0
	OR AL, 1
	MOV	CR0, EAX
	; Commute en PMode
	
	; jump inter segment
	DB 066h
	DB 0EAh
	DW SMALL CODE_32:modeProtege
    DW 0
    DW Index_Code  

CODE_16 ENDS

CODE_32 SEGMENT para USE32 public 'CODE'

	ASSUME CS:CODE_32, DS:CODE_32, ES:nothing, SS:CODE_32

modeProtege	LABEL BYTE

	MOV	AX,	Index_Pile
	MOV	SS,	AX
	
	MOV	AX,	Index_Video
	MOV	DS,	AX
	
	MOV EAX, 0
	MOV BYTE PTR DS:[EAX], 48h				; H
	INC EAX
	MOV BYTE PTR DS:[EAX], 02h				; vert

BOUCLE:
	JMP	BOUCLE

CODE_32 ENDS

DATA_16 SEGMENT USE16
 
  GDT   DW      		Taille_GDT
  DD      				offset Descripteur_Nul
  
  Descripteur_Nul		Descripteur_Segment <0, 0, 0, 0, 0, 0>
  Descripteur_Code		Descripteur_Segment <0FFFFh, 0, 0, 9Ah, 0, 0>
  Descripteur_Donnees	Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>
  Descripteur_Pile		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>
  Descripteur_Video		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>

  Taille_GDT       		EQU $ - Offset Descripteur_Nul

DATA_16 ENDS

DATA_32 SEGMENT USE32

DATA_32 ENDS

PILE 	SEGMENT STACK USE16
 	 DB	512	DUP (?)
PILE 	ENDS

end Debut
I have descriptor segment for video memory, but i can't print my char 'G'.
Char 'A' in real mode is print but not 'H' in protected mode.

I use TASM to compile, and in try this program under MS DOS native, without HIMEM and EMM386 and not under Windows.

This program don't crash, 32 bits code has been good and executed because if i add ; before JMP BOUCLE this program reboot the machine.

Can you help me ? I don't understand why it don't work.

Thank you !

Found !

Posted: Fri Nov 16, 2007 1:16 pm
by Lovmy
Hello !

I have find problem, this is good code:

Code: Select all

.386P

Descripteur_Segment STRUC
	Limite        dw      ?
	Base_0_15     dw      ?
	Base_16_23    db      ?
	Flags_1       db      ?
	Flags_2       db      ?  
	Base_24_31    db      ?
Descripteur_Segment ENDS

Segment_debut	EQU 00h		;	07E0h
Index_Code		EQU	08h		;	001 000
Index_Donnees	EQU	10h		;	010 000
Index_Pile		EQU	18h		;	011 000
Index_Video		EQU 20h		;	100 000 - RPL (2 derniers bits) identifie le niveau de privilege du demandeur
							;       |
							;       TI: 0 = table descripteurs globaux, 1 = table descripteurs locaux de la tache courante

CODE_16 SEGMENT byte USE16 public 'CODE'

	ASSUME CS:CODE_16, DS:DATA_16, SS:PILE
	
debut:
    CLD
    CLI											; Pas d'interruption
    
    MOV	AX, DATA_16								; charge DS avec le segment de donnees
    ADD AX, Segment_debut						; reference en mode boot
    MOV	DS,	AX
    
    MOV AX, 0003h								; Mode texte
    INT 10h
    
    MOV BX, 0B800h								; Affiche un A vert
    MOV ES, BX
    MOV DI, 0
    MOV BYTE PTR ES:[DI], 'A'
    INC DI
    MOV BYTE PTR ES:[DI], 02h					; <---------------- EAX ---------------->
												;                     <------- AX ------>
	MOV	EAX, CODE_32							; 0000 0000 0000 000Y 0000 0000 0000 000X
	ADD EAX, Segment_debut
	SHL	EAX, 4									; 0000 0000 000Y 0000 0000 0000 000X 0000
	MOV	Descripteur_Code.Base_0_15,	AX			;                     <-- AH -> <-- AL ->
	SHR	EAX, 16									; 0000 0000 0000 0000 0000 0000 000Y 0000
	MOV	Descripteur_Code.Base_16_23, AL
	MOV Descripteur_Code.Base_24_31, AH
	; Met a jour le selecteur du segment de Code.
	
	MOV	EAX, DATA_32
	ADD EAX, Segment_debut
	SHL	EAX, 4
	MOV	Descripteur_Donnees.Base_0_15, AX
	SHR	EAX, 16
	MOV	Descripteur_Donnees.Base_16_23, AL
	MOV Descripteur_Donnees.Base_24_31, AH
	; Met a jour le selecteur du segment de Données.
	
	MOV	EAX, PILE
	ADD EAX, Segment_debut
	SHL	EAX, 4
	MOV	Descripteur_Pile.Base_0_15,	AX
	SHR	EAX, 16
	MOV	Descripteur_Pile.Base_16_23, AL
	MOV Descripteur_Pile.Base_24_31, AH
	; Met a jour le selecteur du segment de Pile.
	
	MOV	EAX, 0B8000h
	MOV	Descripteur_Video.Base_0_15, AX
	SHR	EAX, 16
	MOV	Descripteur_Video.Base_16_23, AL
	MOV Descripteur_Video.Base_24_31, AH
	; Met a jour le selecteur du segment de memoire video.
	
	MOV	EAX, DATA_16
	ADD EAX, Segment_debut
	SHL	EAX, 4
	ADD	DWORD PTR GDT[2], EAX
	; Met a jour la variable GDT
	
	LGDT FWORD PTR GDT
	; Charge la GDT
	
	MOV	EAX, CR0
	OR AL, 1
	MOV	CR0, EAX
	; Commute en PMode
	
	; jump inter segment
	DB 066h
	DB 0EAh
	DW SMALL CODE_32:modeProtege
    DW 0
    DW Index_Code  

CODE_16 ENDS

CODE_32 SEGMENT para USE32 public 'CODE'

	ASSUME CS:CODE_32, DS:CODE_32, ES:nothing, SS:CODE_32

modeProtege	LABEL BYTE

	MOV	AX,	Index_Pile
	MOV	SS,	AX
	
	MOV	AX,	Index_Video
	MOV	DS,	AX
	
	MOV EDI, 0;
	MOV BYTE PTR DS:[EDI], 'P'				; P
	INC EDI
	MOV BYTE PTR DS:[EDI], 01h				; bleu
	
BOUCLE:
	JMP	BOUCLE

CODE_32 ENDS

DATA_16 SEGMENT USE16
 
  GDT   DW      		Taille_GDT
  DD      				offset Descripteur_Nul
  
  Descripteur_Nul		Descripteur_Segment <0, 0, 0, 0, 0, 0>

  ;Descripteur_Code		Descripteur_Segment <0FFFFh, 0, 0, 9Ah, 0, 0>		; 64k espace code
  ;Descripteur_Donnees	Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>		; 64K espace donnees
  ;Descripteur_Pile		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>		; 64K espace pile
  ;Descripteur_Video	Descripteur_Segment <0FFFFh, 0, 0, 92h, 0, 0>		; 64K espace memoire video

  Descripteur_Code		Descripteur_Segment <0FFFFh, 0, 0, 9Ah, 0CFh, 0>	;  4G espace code
  Descripteur_Donnees	Descripteur_Segment <0FFFFh, 0, 0, 92h, 0CFh, 0>	;  4G espace donnees
  Descripteur_Pile		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0CFh, 0>	;  4G espace pile
  Descripteur_Video		Descripteur_Segment <0FFFFh, 0, 0, 92h, 0CFh, 0>	;  4G espace memoire video
  ;                                          |       |  |         |   |
  ;                                      L0-15   B0-15  B16-23 L16-19 B24-31

  ; __________________________________________

  ; P = Present en memoire
  ; DLP = Niveau de privilege
  
  ; TYPE = 1xx Code ou 0xx donnees
  
  ;		ST X X
  ;			ST = 0 : ST E W
  ;				si E = 1, limite minimal (utile pour la pile)
  ;					si B = 0, offset maximal de 64K, sinon de 4G
  ;				si W = 1 on peut modifier le contenue du segment
  
  ;			ST = 1 : ST C R
  ;				D = Taille par defaut des opérandes dans le segment
  ;                 0 indique une taille d'opérande de 16 bits
  ;                 1 indique une taille d'opérande de 32 bits
  ;             C = 1 : indique que le segment est Docile
  ;             R = 0 : il est impossible de lire le contenu du segment
  
  ; A est mis a 1 si ce segment a ete accede

  ;       P DLP 1 TYPE A
  ; 9Ah = 1 00  1 101  0 (code)
  ; 92h = 1 00  1 001  0 (donnees)
  ;	              |
  ;              ST
  
  ; __________________________________________
  
  ; G = 1 si page de 1096 octets, sinon octets
  ; AVL = Disponible pour le programmeur
  
  ;      G D/B 0 AVL Limite 16-19
  ; CF = 1 1   0 0   1111	

  ; __________________________________________

  Taille_GDT       		EQU $ - Offset Descripteur_Nul

DATA_16 ENDS

DATA_32 SEGMENT USE32

DATA_32 ENDS

PILE 	SEGMENT STACK USE16
 	 DB	512	DUP (?)
PILE 	ENDS

end Debut
It's bit D of descriptor segment, for 32bits code, it's must be equal to 1.

Thank