Puertos del disco duro:
0x1f0 a 0x1f7, con un total de 8 puertos.
Modos de operación:
- CHS: Especificar cabeza, cilindro y sector.
- LBA: Indicar el bloque lógico inicial y la cantidad de bloques.
Interacción con puertos:
in destino[al / ax], origen[dx / i8] ; Recibir del puerto
out destino[dx / i8], origen[al / ax] ; Enviar al puerto
Se elige ax o al según el ancho del puerto: al para 8 bits, ax para 16 bits.
Implementación de LBA28 para lectura
LBA28 emplea un valor de 28 bits para el número de sector lógico, soportando hasta 128 GB de almacenamiento.
Detalles de puertos:
- 0x1f0: Puerto de 16 bits para transferencia de datos.
- 0x1f1: Registro de estado de errores.
- 0x1f2 a 0x1f7: Puertos de 8 bits.
- 0x1f2: Cantidad de sectores a leer.
- 0x1f3 a 0x1f6 (bits bajos): Dirección lógica inicial de 28 bits.
- 0x1f6 (bits altos): Configuración de dispositivo y modo.
- Bit 4: Selección de disco (0: principal, 1: secundario).
- Bit 6: Modo de direccionamiento (0: CHS, 1: LBA).
- 0x1f7: Comandos: 0x20 para lectura, 0x30 para escritura.
; Definiciones de constantes
BASE_PUERTO equ 0x1f0
MODO_LECTURA equ 0xe0 ; 0b11100000
COD_LECTURA equ 0x20
; Variables globales
InicioSector dd 2 ;
NumSectores db 1
leer_disco:
; Configurar número de sectores
mov al, [NumSectores]
mov dx, BASE_PUERTO + 2 ; dx = 0x1f2
out dx, al
; Enviar los 16 bits inferiores de la dirección
mov ax, [InicioSector]
inc dx ; dx = 0x1f3
out dx, al
mov al, ah
inc dx ; dx = 0x1f4
out dx, al
; Enviar bits superiores de la dirección
mov ax, [InicioSector + 2]
inc dx ; dx = 0x1f5
out dx, al
mov al, ah
mov ah, MODO_LECTURA ; Combinar selección de disco y modo en al
or al, ah
inc dx ; dx = 0x1f6
out dx, al
; Emitir comando de lectura
mov al, COD_LECTURA
inc dx ; dx = 0x1f7
out dx, al
Una vez enviados los parámetros, se espera la respuesta del disco a través del puerto 0x1f7.
El código de estado se analiza mediante los bits 7 y 3.
- Bit 7: 1 indica ocupado, 0 indica disponible.
- Bit 3: 1 indica preparado, 0 indica no listo.
MASCARA_EST equ 0x88 ; 0b10001000
ESTADO_OK equ 0x08 ; 0b00001000
.esperar:
in al, dx
and al, MASCARA_EST
cmp al, ESTADO_OK
jnz .esperar
Posteriormente, se procede a la lectura de los datos.
En este caso, se lee un sector completo de 512 bytes usando transferencia por palabras.
mov dx, BASE_PUERTO
mov cx, 256
.leer_palabra:
in ax, dx
mov [ds:di], ax ; Dirección destino en ds:di, modificable según necesidad
add di, 2
loop .leer_palabra
Uso de la extensión INT 13
Para emplear este método, se requiere una estructura de datos específica:
DescriptorBloque:
TamDesc db 10h
Reservado db 0
NumBloques dw 0
DesplBuffer dw 0
SegBuffer dw 0
DirBloqueBaja dd 0
DirBloqueAlta dd 0
Campos importantes:
- TamDesc: Tamaño fijo de 16 bytes.
- NumBloques: Cantidad de sectores a transferir.
- DesplBuffer y SegBuffer: Dirección completa del buffer destino.
- DirBloqueBaja y DirBloqueAlta: Componentes de 64 bits del número de sector lógico.
Previamente, se verifica la disponibilidad de la extensión INT 13.
.check_ext:
mov ah, 41h ; Función de verificación
mov bx, 55aah
mov dl, 80h
int 13h
cmp bx, 0aa55h
jnz error_handler
Si la extensión es compatible, se realizan las operaciones de lectura y escritura.
.read_block:
mov ah, 42h ; Función de lectura
mov dl, 80h
mov si, DescriptorBloque
int 13h
test ah, ah
jnz error_handler
.write_block:
mov ah, 43h ; Función de escritura
mov dl, 80h
mov si, DescriptorBloque
int 13h
test ah, ah
jnz error_handler
Los errores se pueden gestionra de manera unificada mediante una rutina de manejo de excepciones.