Programación de E/S de disco
IBM ha programó una interface para el manejo de discos que respetan las especificaciones ATA: la interrupción INT 13h. Para especificar las direcciones se emplean los siguientes registros: CH: 8 bits bajos de los 10 bits empleados para especificar el número de cilindro o pista. CL: 2 bits altos de los 10 bits del número de cilindro o pìsta: se almacenan en los bits 6 y 7. Los bits 0-5 son los 6 bits del número de sector. DH: Número de cabezal o lado. Sólo se usan los bits 0-3. Para indicar error, la int13 pone en cero la bandera CF y regresa el código del error en el registro AH. A continuación algunos servicios de la INT 13h: · RESTABLECER EL SISTEMA DE DISCO AH = 00h (servicio o número de función). DL = No. de unidad (80h-FFh para discos duros, 128-255 decimal; 0-7Fh para u. de floppy). Este servicio reinicializa el controlador del disco: cuando se acceda de nuevo a la unidad, se coloca el cilindro en cero. Se emplea después de un error grave. Una operación válida pone en cero la bandera CF; un error activa CF y regresa el código de error en AH. · LEER ESTADO DEL DISCO AH = 01h (servicio o número de función). DL = No. de unidad (80h-FFh para discos duros, 128-255 decimal; 0-7Fh para u. de floppy). La operación se usa para examinar el estado de las operaciones de disco más recientes. Regresa en AL el código de estado, que la última operación puso seguramente en AH. · LEER SECTOR(ES) AH = 02h (servicio o número de función). AL = número de sectores a leer (Base 1: 1..255). CH = bits 0-7, No. de cilindro o pista (LSB del No. de cilindro, 10-bits, 0-1023). CL = bits 6-7, No. de cilindro o pista. CL = bits 0-5, No. de sector inicial (Base 1: 1-63) DH = No. de cabezal o lado (Base 0: 0-15, con traducción puede ser 0-255). DL = No. de unidad (80h-FFh para discos duros, 128-255 decimal; 0-7Fh para u. de floppy). ES:BX = dirección del buffer E/S. Desde una unidad de disquete hay que asegurarse de que un pedido de lectura no cruce el límite de una página DMA (dirección alineada 64K). Es altamente indeseable que el BIOS se encargue del problema por tí. La manera más fácil de cuidarse de esto es simplemente asegurarse de que la dirección del buffer que usas esté siempre alineada sobre un límite igual al tamaño pedido. Si lees cuatro sectores de 512 bytes, hay que alinear el buffer sobre el límite de 2KB. Ejemplo: _sector db 512 dup (?) ; buffer ... mov ah, 2 ; petición de lectura mov al, 1 ; un sector lea bx, 5 ; puntero al buffer mov ch, 4 ; pista 4 mov cl, 3 ; sector 3 mov dh, 0 ; cabeza o lado 0 mov dl, 0 ; unidad 0 (C) int 13h ; llamada al BIOS · ESCRIBIR SECTOR(ES) AH = 03h (número de la función de escritura). El resto de los parámetros son exactamente los mismos que los usados para leer sectores. Recuerda que se debe llenar el buffer apuntado por ES:BX con los datos que se quieren escribir. · OBTENER LOS PARÁMETROS DEL DISCO AH = 08h (número de la función para obener los parámetros de la unidad). DL = número de unidad (igual que para leer/esribir sectores). Esta función regresará con CF=0 si la unidad es válida. Al parecer, no todos los BIOS activan o desactivan correctamente el indicador CF. Cuando se intenta detectar el disco instalado, se debe chequear el número de unidades regresadas en DL, cuando se ha chequeado el primer disco con DL=80h. Esta función regresa el máximo de parámetros CHS en los mismos registros en que ellos se pasaron a INT13, con las funciones o servicios 02h y 03h: BL regresa el tipo de disco CH[0-7] y CL[6-7] regresa el valor máximo del cilindro (menor o igual a 1023). CL[0-5] el máximo número de sectores, ya que los números de sectores son con base uno, este valor es también una cuenta de los sectores. DH regresa el máximo número de cabezales (0-255, una vez más, el número de cabezales-1). DL regresa el No. de unidades conectadas al controlador del disco. ES:DI regresa, para disquetes, la dirección de una tabla de 11 bytes con parámetros de la unidad de floppy: dbp struct dpbCONTROL_TIMERS DW ? dpbMOTOR_OFF_DELAY DB ? dpbBYTES_PER_SECTOR DB ? dpbSECTORS_PER_TRACK DB ? dpbGAP_LENGTH DB ? dpbDATA_LENGTH DB ? dpbFORMAT_GAP_LENGTH DB ? dpbFORMAT_FILLER_BYTE DB ? dpbHEAD_SETTLE_TIME DB ? dpbMOTOR_START_TIME DB ? dbb ends (dbp: disk parameter block - bloque de parámetros del disco) Notas: Es común excluir el último cilindro de la información regresada por estas funciones. En los compatibles IBM PCs, este cilindro se reserva para diagnósticos del fabricante. Si se escribe un sistema operativo o una utilidad de partición, se podría dejar como una opción al usuario incluir o no este cilindro en una partición. Recordar siempre que la utilidad debería hacer una lectura/escritura/verificación del cilindro antes de intentar usarlo. · CHEQUEO DE INSTALACIÓN DE EXTENSIONES INT13 AH = 41h DL = número de unidad (igual que para leer/esribir sectores). BX = 055AAh Regresa: BX = 0AA55h (en orden invertido) y CF=0 si las extensones son soportadas por la unidad. Esta llamada también regresa en CX información sobre las subfunciones soportadas. · LECTURA EXTENDIDA DE SECTOR(ES) AH = 42h DL = número de unidad (igual que para leer/esribir sectores). DS:SI = puntero a la estructura del paquete pedido al disco (disk request packet structure.) Formato del paquete requerido: BYTE Tamaño del paquete (10h) BYTE Reservado (00h) WORD Conteo de sectores WORD Desplazamiento (offset) del buffer WORD Segmento del buffer QWORD 64-bits con la dirección del bloque lógico · ESCRITURA EXTENDIDA DE SECTOR(ES) AH = 43h DL = número de unidad (igual que para leer/esribir sectores). DS:SI = puntero a la estructura del paquete pedido al disco (disk request packet structure.) Ee lo mismo que el servicio anterior. · OBTENCIÓN DE PARÁMETROS EXTENDIDOS DE LA UNIDAD (EXTENDED GET DRIVE PARAMETERS) AH = 48h DL = número de unidad (igual para lectura/escritura de sectores). DS:SI = buffer para la estructura de parámetros de la unidad. (Estructura): WORD Tamaño del buffer, 1Ah, 1Eh or 42h, depende de la versión de las extensiones. WORD Indicadores (flags) de información DWORD # de cilindros físicos DWORD # de cabezales físicos DWORD # de sectores físicos QWORD 64-bits con el número total de sectores de la unidad. Notas: La tabla de arriba describe los valores regresados por una llamada en la versión 1.0. Mayor información sobre esta materia, puede encontrarase en la lista de interrupciones de Ralf Browns: http://www-2.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html ------------------------------------ · Ejemplo de código INT13: MBRREST ------------------------------------ Con esta información ya podemos escribir nuestra rutina para salvar el sector de arranque de un disco. El algoritmo es simple: · Creamos un archivo · Leemos el sector de arranque del disco en un buffer de 512 bytes (512 bytes es el tamaño de un sector) · Escribimos el contenido del buffer en el archivo · Cerramos el archivo Para crear, leer y escribir un archivo en disco, emplearemos la interface suministradas por los servicios 3Ch-40h de la interrupción 21h de DOS. Quiere decir que este programa supone DOS. Luego de la rutina para hacer un respaldo del sector de arranque del disco seguiremos con otra que escriba en el inicio del disco un archivo que especifiquemos: · Abrimos un archivo para su lectura · Leemos de él un bloque de 512 bytes y lo ponemos en un buffer. · Copiamos el contenido del buffer en el primer sector del disco. · Revisamos si ya hemos copiado todo el contenido del archivo. Si ya lo hicimos, cerramos el archiv o y salimos; sino copiamos el siguiente bloque del archivo hasta que hallamos copiado todo el contenido del archivo e el disco Agregaremos también el código para obtener argumentos desde la línea de órdenes y crear un respaldo del sector de arranque original. El programa sólo hará el respaldo si no encuentra el fichero binario que se escribirá en el primer sector del disquete. ; ----------------------------------------------------------------------- TITLE MBRREST.ASM: Utilidad para escribir el MBR en una unidad de floppy ; --------------------------------------------------------------------------------- ; Para ensamblar con TASM: ; tasm mbrrest ; tlink /t mbrrest ; Esto producirá un archivo mbrrest.com ; --------------------------------------------------------------------------------- .model tiny sectors_per_track equ 18 tracks_per_side equ 80 .code org 100h entry: lea si, msg1 ; desplegar el texto de copyright :-) call _szDisplay ; ------------------------------------------------------------ ; Obtener el nombre del archivo pasado en la línea de órdenes ; ------------------------------------------------------------ mov si, 80h lodsb ; obtener número de caracteres test al, al ; ¿el número es cero? je no_file ; si es cero saltar ; saltarse los espacios is_space: lodsb ; obtener el caracter cmp al, 20h ; ¿es un espacio? je is_space ; saltar si es un espacio cmp al, 13h ; se alcanzó el final de la línea je no_file ; saltar si se llegó al final dec si ; ajustar el puntero push si ; salvar la dirección de la cadena ; buscar el final de la cadena next: lodsb cmp al, 13 ; ¿se alcanzó el final de línea? jne next ; revisar siguiente si no se alcanzó? ; poner cero al final de la cadena dec si ; apuntar al final mov byte ptr [si], 0 ; poner cero al final pop si ; restablecer la direción de la cadena jmp _with_file ; proceder a hacer el respaldo no_file: dec si mov byte ptr [si], 0 ; SI apunta a cero _with_file: ; --------------------------------- ; Hacer un respaldo del MBR actual ; --------------------------------- mov ax, 0 ; reestablecer sistema de disco mov dl, al ; 0 para floppy, cambiar a 80h para int 13h ; discos duros ; Verificar si se trabaja sobre una unidad de floppy: se lee en ; el sector 18 de la primera pista; si da error, no es una unidad ; de floppy de 1.44MB mov ah, 2 ; leer mov al, 1 ; un sector mov dh, 0 ; cabezal o lado 0 mov dl, 0 ; disquete: unidad A mov ch, 0 ; pista 0 mov cl, 18 ; sector 18 lea bx, buffer int 13h or ah, ah ; Si ah=0, se pudo leer el sector 18 je is_1_44 ; y el disquete es de 1.44MB lea si, msg3 ; Si no es un disquete de 1.44MB call _szDisplay ; desplegar el mensaje 3 jmp close_file ; cerrar el archivo y salir is_1_44: ; Lectura CHS del MBR mov bp, 4 ; leer el sector de arranque 4 veces ... read: lea di, buffer ; buffer para la transferencia de datos mov cx, 512 ; tamaño del buffer = bytes por sector call _ZeroMemory ; Limpiar el buffer mov ah, 2 ; leer mov al, 1 ; un sector mov dh, 0 ; cabezal o lado 0 mov dl, 0 ; disquete: unidad A (poner 80h para disco duro) mov ch, 0 ; pista 0 mov cl, 1 ; sector 1 lea bx, buffer int 13h dec bp jnz read ; Creación del fichero de respaldo mov ax, 3C00h ; crear el fichero de respaldo mov cx, 0 ; atributo normal lea dx, bu_file int 21h mov bx, ax ; mover el handle del fichero a BX ; Escritura del buffer en el fichero de respaldo mov ah, 40h ; escribir el mbr en boot.bak mov cx, 512 ; un sector = 512 bytes lea dx, buffer int 21h jc error_writing ; Cierre del fichero de respaldo mov ah, 3Eh ; cerrar el archivo creado para respaldo int 21h jmp restore error_writing: lea si, error_w no_name: call _szDisplay int 20h ; ------------------------------------------------------------------------------- ; ---------------------------- ; Escribir el archivo en disco ; ---------------------------- restore: ; ¿Se pasó nombre de archivo como parámetro? lodsb test al, al jne @00 ; Si no se pasó nombre, avisar y salir lea si, warning jmp no_name ; Abrir fichero para lectura @00: push si lea si, msg2 ; desplegar el mensaje de aviso call _szDisplay pop si dec si mov ax, 3D00h ; abrir fichero indicado para su lectura mov dx, si int 21h jc error ; error abriendo el fichero? mov bx, ax ; mover el handle del fichero a BX ; Obtener el tamaño del archivo mov ax, 4202h mov cx, 0 mov dx, cx int 21h jc error ; error abriendo el fichero? ; Verificar si cabe en una unidad de floppy cmp dx, 016h jl good_for_floppy1 bad_for_floppy: lea si, msg3 call _szDisplay jmp close_file ; cerrar el fichero error: lea si, error_r ; desplegar mensaje de error call _szDisplay int 20h ; regresar a DOS ... good_for_floppy1: cmp dx, 015h jl good_for_floppy2 cmp ax, 0F900h jg bad_for_floppy ; Obtener el No. de sectores del archivo good_for_floppy2: mov cx, 200h div cx mov uSector, ax or dx, dx je rounded inc word ptr [uSector] rounded: mov ax, 4200h mov cx, 0 mov dx, cx int 21h jc error ; error abriendo el fichero? ; Leer el fichero mov track, al mov head, al inc ax mov sector, al get_next_sector: lea di, buffer mov cx, 512 call _ZeroMemory mov ah, 3Fh ; leer el fichero en el buffer mov cx, 512 lea dx, buffer int 21h pushf or ax, ax je write_sector popf jnc write_sector ; ¿hubo error? lea si, error_r ; si hubo error, call _szDisplay ; avisar y jmp close_file ; cerrar el fichero write_sector: popf push ax ; Escritura del fichero en el disco mov ax, 0 ; restablecer el sistema de disco mov dl, 0 ; para disquete: mov dl, 0 int 13h push bx mov bp, 4 ; escribir el MBR cuatro veces ... write: mov ax, 0301h ; AH: 3, escribir, AL: 1 sector mov dh, head mov dl, 0 mov ch, track mov cl, sector lea bx, buffer ; dirección del buffer a escribir int 13h dec bp jnz write pop bx ; Si se llega al sector 18 (sectors_per_track), se escribe ; en el siguiente track y se comienzade nuevo el conteo de ; sectores inc sector cmp sector, sectors_per_track jne count_sector mov sector, 1 inc track ; Si se llega a la pista 80 (tracks_per_side), se lee en el ; otro lado del disquete cmp track, tracks_per_side jne count_sector inc side ; Si hay que leer el lado 3, se termina porque el disquete ; sólo tiene 2 lados cmp side, 3 je close_file count_sector: dec uSector ; Disminuir conteo de sectores a copiar jne get_next_sector ; Si no se llegó a cero, copiar el siguiente ; Cerrar el fichero close_file: mov ah, 3Eh ; cerrar el fichero int 21h int 20h ; regresar a DOS ... _szDisplay: push si _print_string: lodsb test al, al jz _exit_szDisplay mov bx, 000Fh mov ah, 0Eh int 10h jmp _print_string _exit_szDisplay: pop si ret _ZeroMemory: push di mov al, 0 rep stosb pop di ret file db 'BOOT.BIN',0 bu_file db 'BOOT.BAK',0 msg1 db 'MBRREST Version 2.0 (c) 2002', 13, 10 db '----------------------------', 13, 10 db 'Haciendo respaldo del sector de arranque...', 13, 10, 0 msg2 db 'Escribiendo archivo en el inicio del disco...', 13, 10, 0 msg3 db 'No se trabaja con un disquete de 1.44 MB',13, 10, 0 warning db 'No se introdujo el nombre del archivo a escribir. ' db 'No se escribir', 0A0h, 20h, 'en el disco', 13, 10, 0 error_r db 'Error leyendo el binario.', 13, 10, 0 error_w db 'ERROR: No se pudo escribir el sector de arranque a ' db 'boot.bak', 13, 10, 0 head db 0 track db 0 sector db 0 side db 0 uSector dw 0 buffer db 512 dup (0) END entry *NOTA* Nota que el archivo de respaldo simpre lleva el mismo nombre: "BOOT.BAK" y que es copiado en el mismo directorio del archivo copiado al disquete. Esto quiere decir que, si se va a restaurar este archivo, *debe cambiársele el nombre*, sino cuando haga el respaldo nuevo, sobreescribirá el "BOOT.BAK" anterior y el archivo que se copiará no será el anteriormente salvado. Para usar MBRREST, hay que usar la siguiente orden: MBRREST image.bin donde " image.bin" es el nombre de la imagen a copiar en los primeros sectores del disquete. Si no se le pasa nombre, MBRREST sólo hará un respaldo del primer sector del disquete. Esta herramienta no te funcionará correctamente desde Windows 2000, ya que protege contra escritura en discos. - Análisis de MBRREST - La primera observación que hay que hacer es que debemos obtener un fichero .COM, no .EXE. Un fichero .COM usa siempre modelo de memoria TINY: un único segmento para datos y código. Tampoco es necesario definir una pila: los ejecutables con formato COM generan automáticamente la pila. Como estos archivos usan un segmento para código y datos, su tamaño está restringido a 64KB. Cuando DOS monta el programa, pone en DS y CS la dirección del PSP (Prefijo de Segmento el Programa). El PSP es una pequeña base de datos de 256 (100h) bytes que construye DOS en el límite de un párrafo (16 bytes) en la memoria interna disponible cuando carga un programa en memoria, inmediatamente después se cargará el programa mismo. El PSP también forma parte del segmento único de 64 KB. Como el programa comienza a ejecutarse inmediatamente después del PSP, debe indicársele al ensamblador que genere el código a partir del desplazamiento 100h (256). Esto se le indica con la directiva ORG, inmediatamente después de iniciar el segmento de código con .code o con la directiva SEGMENT: .code ORG 100h Los registros CS y DS ya tienen la dirección apropiada, así que no hay que iniciarlos como se hacía con los archivos .EXE.
Porque desactiváis la opción de copiar las páginas web, programáis códigos inútiles, acaso no sabéis que mientras exista buscadores que presenten el código fuente de las paginas siempre será posible copiar cualquier pagina web de hecho tengo una copia de esta página solo como reto personal para verificar esta posibilidad, aunque realmente mientras se siga en la línea de código interpretado como es el HTML y no código compilado es inútil evitar que cualquier programador no necesariamente hábil copie sin problemas cualquier pagina, es mas alentáis a esa posibilidad solo por el hecho de prohibir es un reto que dejáis a la imaginación humana
ResponderEliminarPermiteme, te aplaudo de pie, congrats ;)
EliminarTan fácil como es CTRL + U, y ya lo copias
ResponderEliminar:V
ResponderEliminarqe sonso, ya lo copie todo
ResponderEliminar