; Mostrar en pantalla 25 lineas de caracteres. La linea superior
; debe contener letras 'A', la segunda linea letras 'B' y asi sucesivamente
; hasta la letra 'Y'.
; Registros usados:
;    CL = Fila, CH = Columna, SI = Puntero, BL = Letra a mostrar
    
       bits 16               ;El código a continuación va en 
                             ;segmento de código de 16 bits.
inicio:
%include "init_pci.inc"
       xchg bx,bx

       jmp pasaje_a_modo_protegido
   
       align 8               ;Optimización para leer GDT más rápido.
   
GDT:
       dq 0                  ;Descriptor nulo
     
CS_SEL equ $-GDT             ;Selector de código
                             ; Base FFFF0000, límite 0000FFFF.
                             ; Granularidad = 0, límite = 0FFFF.
       dw 0xffff             ;Límite 15-0
       dw 0                  ;Base 15-0
       db 0xff               ;Base 23-16
       db 10011010b          ;Derechos de acceso
                             ;Bit 7=1 (Presente), Bits 6-5 = 0 (DPL),
                             ;Bit 4=1, Bit 3=1 (código), Bit 2 = 0
                             ;(no conforming), Bit 1=1 (lectura),
                             ;Bit 0=0 (accedido)
       db 0x40               ;G=0, D=1, límite 19-16
       db 0xff               ;Base 31-24
         
DS_SEL equ $-GDT             ;Selector de datos flat
                             ; Base 00000000, límite FFFFFFFF.
                             ; Granularidad = 1, límite = FFFFF.
       dw 0xffff             ;Límite 15-0
       dw 0                  ;Base 15-0
       db 0                  ;Base 23-16
       db 10010010b          ;Derechos de acceso
                             ;Bit 7=1 (Presente), Bits 6-5 = 0 (DPL),
                             ;Bit 4=1, Bit 3=0 (datos), Bit 2 = 0
                             ;(dir expansión normal), Bit 1=1 (R/W),
                             ;Bit 0=0 (accedido)
       db 0xcf               ;G=1, D=1, límite 19-16
       db 0                  ;Base 31-24
      
tam_GDT equ $-GDT            ;Tamaño de la GDT.      
 
imagen_gdtr:
       dw  tam_GDT - 1       ;Límite GDT (16 bits).
       dd  0xffff0000 + GDT  ;Base GDT (32 bits).
     
pasaje_a_modo_protegido:
     
       cli                   ;Deshabilitar interrupciones.
       o32 lgdt [cs:imagen_gdtr] ;Cargar registro GDTR.
                                 ;Con prefijo 0x66 que agrega el o32
                                 ;se usan los cuatro bytes de la base.
                                 ;Sin o32 se usan tres.
       mov eax, cr0           ;Pasar a modo protegido.
       or  eax, 1
       mov cr0, eax
     
       jmp CS_SEL:inicio_32   ;Cambiar el CS al selector de
                              ;modo protegido.
       BITS 32                ;El código a continuación va en 
                              ;segmento de código de 32 bits.
inicio_32:
 
       mov ax, DS_SEL         ;Cargar DS con selector que apunta a
       mov ds, ax             ;descriptor de segmento de datos flat.
       mov bl, "A"            ;Código ASCII del carácter
       mov cl, 0              ;Fila
       mov esi, 0xb8000       ;Puntero
ciclo_externo:
       mov ch, 0              ;Columna
ciclo_interno:
       mov [esi], BL          ;Escribo carácter en pantalla
       mov BYTE [esi+1], 0x07 ;Escribo atributo en pantalla
       add esi, 2             ;Incremento el puntero
       inc ch                 ;Incremento columna
       cmp ch, 80             ;Completé las 80 columnas de la línea?
       jne ciclo_interno      ;Saltar si no es así.
       inc cl                 ;Incremento la fila
       inc bl                 ;Incremento el código ASCII del carácter
       cmp cl, 25             ;Verifico si completé las 25 filas.
       jne ciclo_externo      ;Saltar si no es así.
       jmp $                  ;Colgarse.

       times 0xFFF0 - ($ - inicio)  db 0   ;Primer relleno.
     
       bits 16                ;El código a continuación va en 
                              ;segmento de código de 16 bits.
                             
reset:                        ;Dirección de arranque del procesador.
       jmp inicio - $$        ;Saltar al principio de la ROM.
     
       times 0x10 - ($ -reset) db 0        ;Segundo relleno.
