=======================================================
Introduccin a la programacin en lenguaje ensamblador
para procesadores Intel serie x86 y compatibles (V)
=======================================================

Por nmt
numit_or@cantv.net

===========================================================
PRIMEROS CONTACTOS CON EL SISTEMA: OPERACIONES CON EL DISCO
===========================================================

--------------------------------------------------------
  CONTENIDO

  - Primera utilidad

  - El Disco Duro
	 LBA - Logical Block Address: Direccin Lgica del Bloques
	 reas del disco

  - El sector de arranque
	 Anlisis del cdigo
	 NOTA: MBR para NASM

  - Programacin de E/S de disco

  - Ejemplo de cdigo INT13: MBRREST
	 Anlisis de MBRREST
		 Operaciones con archivos en DOS
			 NOTA: la instruccin DIV

  - Cdigo del MBR (Master Boot Record: Sector Maestro de Arranque)

  - Unas palabras sobre las particiones

  - Escribir un sector de arranque

  - APNDICES
	 Apndice 1: Desensamblaje de un MBR
	 Apndice 2: Anidamiento de la particin
	 Apndice 3: Enlace de la tabla de particin
	 Apndice 4: Indicadores de tipo de particin




=================
Primera utilidad
=================
Hay  muchas  rutinas  y  programas  que resulta mejor escribirlas en ensamblador. 
Es en este tipo de rutinas en las que vamos a concentrarnos. Entre estas rutinas, 
estn  las  que  requieren  una interaccin directa con dispositivos de hardware, 
como  el  controlador  de vdeo o el disco duro, ah donde se requiere un control 
estricto.  Como  en  el futuro mediato vamos a revisar el uso de los registros de 
sistema del procesador,  y estos encuentran su campo ms propicio en el diseo de 
sistemas operativos,  nos  concentraremos  ahora  en una rutina que nos abrir el 
camino hacia ello.

Vamos a escribir ahora un programa sencillo pero muy til,  que  salva  el sector 
de arranque, el primero de un disquete en un archivo de respaldo, y luego,  si se 
le pide,  escribe un archivo en los primeros  sectores  del  disquete.  Esto  nos
permite obtener el sector de arranque de los sistemas puestos  en disquetes  para
su estudio o necesaria restauracin en momentos "amargos", y tambin copiar en el
disquete bootstraps, rutinas de arranque que vayamos escribiendo.

Estudiaremos la manera cmo arranca el sistema y disear nuestra propia rutina de 
arranque.  Es que en este estudio es donde cabe investigar los modos de operacin 
del procesador, ah donde el sistema operativo no representa una traba.

Escribir esta  utilidad no requieren mucho conocimiento: necesitamos saber qu es 
el  sector de  arranque  de un disco, cmo lo obtenemos y cmo lo guardamos en un 
archivo,  como  leemos un  archivo y ponemos su contenido en un sector del disco. 
Para hacer el trabajo completo,  escribiremos nuestro propio sector de arranque y 
lo probaremos.


NOTA: En esta leccin vamos a tratar con rutinas que escriben sobre disquetes en
unidades de floppy.  Hay  que  seguirla  con  detenimiento,  pues  no  me  puedo 
responsabilizar con el mal uso que se haga con las rutinas aqu expuestas.


-------------
El Disco Duro
-------------
La sigla CHS significa Cilinder-Head-Sector --Cilindro-Cabezal-Sector--, que son
los elementos que constituyen el formato de un disco duro.

Un  disco  duro consiste en uno o ms platos rotativos.  Cada plato tiene varias 
pistas concntricas numeradas empezando por cero desde la pista ms externa.  Si 
se trata de un disco formateado  siguiendo  la  especificacin  ATA,  cada pista 
estar formateada en sectores (S) de 512 bytes donde se almacena la informacin. 
Los datos son escritos o ledos a travs de un cabezal,  cuya posicin determina 
la pista leda.

El cilindro (C) es el conjunto vertical de todas las pistas con el mismo  nmero 
en  cada superficie de un disco duro.  As como se identifica el nmero de pista 
con el de cilindro,  a  la  superficie  o lado del disco se le identifica con el 
cabezal (H).

Para el manejo de discos, el BIOS ofrece varios servicios que pueden solicitarse
a travs de la interrrupcin 13h.


LBA - Logical Block Address: Direccin Lgica del Bloques
---------------------------------------------------------
El  formato  CHS no es la manera lgica de direccionar sectores del disco.  Los 
sistemas operativos, que trabajan en alto nivel, tratan el disco como un stream 
(un continuum) de sectores,  usando  un esquema de numeracin simple comenzando 
con cero, que sera la direccin del primer sector del dispositivo,  y a partir
de este sector se direccionan el resto. A este esquema de direcionamiento se le 
llama LBA (Logical Block Addressing:  Direccionamiento Lgico por Bloques).  El 
estndar  ATA exige que la direccin cilndro 0,  cabeza 0, sea el mismo sector 
que el direccionado por LBA 0. 

LBA  es un esquema ms atractivo que CHS porque presenta las direccciones  como 
deberan ser vistas en un sistema de archivos.  Pero CHS ya exista mucho antes 
que el LBA, as que hubo que disear un mtodo de traduccin. Luego veremos los 
problemas y algoritmos concernientes a los mtodos de traduccin.


reas del disco
---------------
El  disco  duro se divide en dos reas pincipales:  un rea de sistema y una de 
arranque.

	 rea de sistema
	  La primera rea del disco,  donde  se mantiene informacin que usa el
	  sistema operativo para el arranque y el manejo de archivos.

	  Se subdivide en:
	  	 Registro de arranque: sector de 512 bytes con cdigo y datos
	  	  necesarios  para  cargar  los  archivos  de sistema desde el
	  	  disco hasta la memoria. Para DOS, tambin contiene una tabla
		  conocida como bloque de parmetros del BIOS (BIOS  Parameter 
		  Block: BPB) que contiene informacin sobre la geometra y el 
		  formato del disco, etc. Incluye adems  otra tabla con datos
		  sobre las particiones del disco.  Esta  ltima tabla no est
		  presente en los disquetes de unidad de floppys.

		 Tabla de asignacin e archivos (FAT: File Allocation Table):
	  	  Tabla con informacin para asignar  espacio  en disco duro a
		  los archivos. Contiene una entrada para cada grupo en disco.
	  	  
	  	  Un grupo es un conjunto de sectores que el sistema operativo 
		  trata como una unidad  de  almacenamiento.  Su tamao es una 
		  potencia de 2.  Un  grupo  es  la  unidad  ms  pequea para 
		  localizacin de espacio que maneja DOS:  el espacio usado en  
		  un  disco  por cada archivo es medido en cantidad de grupos.
		  As  que si un arhivo tiene una cantidad de datos menor a un 
		  grupo,  DOS reservar todo el espacio equivalente a un grupo 
		  para el archivo. El espacio restante quedar sin uso.

	  	  La FAT comienza en el  sector 2,  inmediatamente despus del
	  	  sector de arranque. La cantidad de sectores que se le asigna
		  est en el BPB,  en  el  desplazamiento  16h  del  sector de 
		  arranque.  Generalmente  existe  una copia adicional de ella 
		  por razones de seguridad  y que se encuentra en los sectores 
		  despus de la primera FAT.  El desplazamiento 10h del sector 
		  de arranque, dentro del BPB, indica el nmero de copias.

		  La FAT  es una base de datos sobre archivos que asocia algn 
		  nmero de grupo con un archivo de datos.  El  tamao de cada
		  entrada  de  la  FAT  puede  variar  entre 12 y 16 bits para 
		  unidades de  floppy  y  32 para unidades de  disco duro.  El
		  tamao de las  entradas de la FAT influyen en la posibilidad
		  de direccionar en discos de tamao considerable.

		  Los  directorios  de las  FAT12 y FAT16  estn pensados para 
		  sistemas  de a rchivos  que  soportan  hasta 65,525 grupos y 
		  limitadas a 2 GB.  Trabajan mejor sobre pequeas unidades de 
		  hasta 500 MB debido al tamao de los  grupos.  Para unidades
		  mayores se usa FAT32.

		  FAT32 no reconocer volmenes FAT ni NTFS de otros  sistemas 
		  operativos,  pero soporta unidades de hasta 2 terabytes. Usa 
		  grupos ms pequeos (por ejemplo, 4k grupos hasta 8 gigs).

		  FAT32X  es una formna de  FAT32 creada por FDISK de  Windows 
		  para  particiones que superan los 8 GB y los  1024 cilindros 
		  del disco son  sobrepasados.  La tabla  de  localizacin  de 
		  archivos es movida la final del disco.

		  VFAT (Virtual File Allocation Table)  es una versin de modo
		  protegido del sistema de archivos de la FAT,  usada por W95.
		  Es compatible con el sistema FAT, la principal diferencia es 
		  el soporte de nombres largos.

		  Bajo FAT32,  el  PBP aumenta su nmero de entradas y algunos
		  de sus campos originales quedan inutilizados.


	  	 Directorio: Para cada archivo, el sistema operativo crea una 
		  entrada de directorio de 32  bytes con informacin sobre los
		  archivos  en  el rea de datos.  Esta informacin incluye el
		  nombre del archivo,  extensin,  tamao, nmero relativo del  
		  primer grupo, etc.  Cada entrada incluye una indicacin  del 
		  grupo donde comienza el archivo;  este  mismo  nmero indica
		  una entrada de la FAT donde se ha de encontrar el nmero del 
		  siguiente grupo de datos del archivo.

		  Los grupos se cuentan a partir del final del directorio; as
		  que el grupo 1 ser el primero despus del directorio.

		  Bajo FAT32,  el sistema  puede usar cualquiera de las copias 
		  de la FAT, no slo una.  El  directorio  ahora es localizado 
		  libremente,  ya  no  hay  lmite en el nmero de entradas de  
		  directorios en el directorio raiz,  condicin necesaria para  
		  permitir entradas de directorio para nombres de archivo --la
		  FAT12 y FAT16 slo permiten  nombres  de hasta 8 caracteres.
		  El  directorio  raz ya no est almacenado en un lugar fijo: 
		  hay una indicacin del nmero del grupo dnde comienza en el 
		  BPB extendido de la FAT32.  Las  entradas del directorio del 
		  disco no cambian  excepto  por  los  dos  bytes  previamente 
		  reservados para atributos extendidos, que ahora contienen la 
		  palabra de orden ms alto del nmero del cluster inicial.

		  Para ubicar el directorio en FAT32, hay que revisar el campo
		  2Ch del PBP extendido,  que indica el nmero del grupo donde
		  comienza.


	*NOTA 1*
	El  sistema  de  manejo  de archivos aqu presentado corresponde a los
	sistemas Microsoft.  Otros  sistemas  han sido propuestos para superar
	algunas ineficiencias del sistema FAT, que  pone todos los  punteros a 
	los archivos en disco en una misma tabla de forma aleatoria. Por esto,
	para  encontrar  cualquier  archivo  siempre  se necesita toda la FAT, 
	incluso si se trabaja con slo uno. 

	El  mtodo alternativo propuesto por UNIX fue asociar una tabla a cada
	archivo, llamada nodo-i. Dicha  tabla  se  halla  en  el mismo disco y
	contiene  informacin sobre atributos de proteccin y de conteo,  como
	10 nmeros de bloques de disco y 3 de bloque indirectos. Si un archivo
	crece por encima de los 10 bloques, se adquiere uno nuevo desocupado y 
	se coloca un puntero indirecto a l.  En  este nuevo bloque se colocan 
	punteros  para  los  nuevos bloques  de  disco.  Si hay un archivo que 
	requiere ms bloques de los que puede direccionar  el  nuevo bloque de 
	punteros,  entonces este bloque se usa para apuntar a un nuevo bloque, 
	tambin con punteros a bloques del archivo;  ya  el segundo bloque  no 
	apunta a bloques de datos sino a bloques de punteros.  Se tiene as un
	sistema de punteros a bloques y de punteros a bloques con punteros.


	*NOTA 2*
	El  boot  record  en  unidades FAT32 requiere 2 sectores (debido a la
	expansin  de  los  campos  en el BPB). As que el nmero de sectores
	reservados  en  unidades  FAT32  es mayor que en FAT16,  generalmente
	32.  Esta  area  expandida permite almacenar dos copias completas del 
	sector  de  arranque y un sector donde es puede almacenar la cantidad
	de  espacio  libre, y algn otro tipo de informacin sobre el sistema 
	de archivos.


	 rea de datos
	  Espacio del disco donde  se  almacenan los  archivos  de  datos  de 
	  sistema  y  de  usuario.  Al  inicio se encuentran los archivos del 
	  sistema, como IOSYS.SYS de DOS.  A continuacin siguen los archivos 
	  de  usuario,  a  no ser que no hayan archivos de sistema y entonces 
	  los archivos de  dato s del  usuario  iniciarn el rea de datos el 
	  disco.


El sector de arranque
---------------------
El  sector de arranque en un disco siempre es el primer sector de la  primera 
pista  sobre  el  primer  cabezal.  Cuando  la  computadora  es  escendida (o 
reiniciada),  el BIOS  ejecuta  el  POST  (Power On Self Test: Auto-Prueba de 
Energa);  inicializa  todos  los  datos,  luego  busca un sector de arranque 
vlido.  Primero  revisa el floppy A, si as est especificado,  luego revisa 
C. Si no encuentra un sector de arranque, se ejecuta la int18h, que inicia el 
ROM BASIC.  Para  identificar un sector de arranque vlido, el BIOS revisa en 
el deplazamiento  510 del  sector de arranque y comprueba si aparece el valor 
0AA55h. Si el BIOS encuentra el sector de arranque, lo lee (512 bytes)  y  lo 
guarda en la RAM en 0:7C00h o 07C0h:0. Luego pasa el control a esa  direccin 
y se ejecuta el cdigo en el sector de arranque.  En este punto,  todo lo que 
ha sido inicializado es el rea de datos del BIOS (en 0:400h o 40h:0)  y  las 
interrupciones del BIOS (10h-1Ah).  La memoria  est casi totalmente sin uso, 
pero no necesariamente limpia.

Generalmente, en la direccin 0 del sector de arranque, hay un salto (jmp) al 
cdigo de arranque, que en el sistema operativo DOS est en el desplazamiento 
1Eh o 3Eh,  dentro del mismo sector de arranque,  inmediatamente  despus del 
BPB, con informacin sobre el formato del disco.

Abajo un ejemplo que se puede usar como plantilla para escribir el cdigo de 
un sector de arranque:


; ---------------------------------------------------------------------------------
  TITLE MBR.ASM: Plantilla para la escritura de MBRs
; ---------------------------------------------------------------------------------
; Code+Data debe tener un tamao menor que 510 bytes!
; ---------------------------------------------------------------------------------
	.model tiny
	.code
	org 0
	EntryPoint:
  		db 0EAh  ;jmp far SEG:OFS    ; En este momento estamos en 0:7C00
  		dw OFFSET AfterData, 7C0h    ; Esto hace que estemos en 7C0:0

	; Poner cualquier dato aqu

	AfterData: 
		push CS
		pop  DS		; actualiza DS para que sea 7C0h en vez de 0

	; Poner aqu el cdigo!
       
		jmp $		; Terminar aqu

	org 510			; Hacer el fichero de 512 bytes de tamao
	dw 0AA55h		; Agregar la signatura de arranque

	END EntryPoint

; ---------------------------------------------------------------------------------
	; Para ensamblar con TASM:
	;	tasm mbr
	;	tlink mbr
	; Esto producir un archivo mbr.com
; ---------------------------------------------------------------------------------


 - Anlisis del cdigo: directiva ORG -
Aqu hay varios detalles que son dignos de analizar.  Primero  una directiva
nueva: ORG.

Para  llevar una cuenta de las posiciones relativas a un segmento de datos o 
de cdigo, el ensamblador utiliza un contador de localidades.  Al inicio, el
contador es puesto en 0. Con cada instruccin, el contador se incrementa  en 
la cantidad correspondiente al tamao de la instruccin.

Si se desea iniciar o cambiar el contenido del contador de  localidades,  se 
puede usar la directiva ORG, que de esta manera cambiar la localidad de los 
elementos siguientes. El formato es:

		ORG	expresin

Esta directiva es muy til  especialmente cuando  deseamos que inicien,  por
ejemplo, en la localidad 0, por ejemplo:

		org	0

Luego unas instrucciones curiosas:

	EntryPoint:
  		db 0EAh  ;jmp far SEG:OFS    ; En  este  momento  estamos en 
					     ; 0:7C00
  		dw OFFSET AfterData, 7C0h    ; Esto hace que estemos en 7C0:0

la primera define un byte inicializado con 0EAh, la segunda define dos datos
con tamao word, el primero es la direccin de  "AfterData",  y  el  segundo 
inicializado con 07C0h.

El valor 0EAh es el cdigo de operacin de "jmp far":  cuando escribimos  en
lenguaje ensamblador, el cdigo escrito debe ser ensamblado: debe traducirse 
su contenido  a  cdigo  binario  y puesto en otro archivo, generalmente con
extensin .OBJ. El ensamblador se encarga de este trabajo.  Cada instruccin 
en ensamblador tiene su correspondiente cdigo binario de operacin  con  el 
que realmente trabaja la mquina.  El  valor  0EAh  ser interpretado por el 
procesador como un salto lejano.

Un salto lejano, como ya vimos tiene el siguiente formato:

		SEGMENTO:DESPLAZAMIENTO

se requieren dos valores tamao word,  uno  para indicar el segmento y otro 
para un desplazamiento dentro del segmento. La instruccin:

  		dw OFFSET AfterData, 7C0h

indica dnde debe pasar el control la instruccin "jmp far":

		jmp far 07C0h:offset AfterData

Quiere decir que la primera instruccin despus de  este salto debe  estar
en 07C0:0

Las instrucciones:

 		push CS
		pop  DS		; actualiza DS para que sea 7C0h en vez de 0

pasan  el contenido de CS, con la base del archivo en memoria (07C0h) a DS, 
usando la pila.  Recurdese que no se pueden mover datos inmediatos o desde 
la memoria directamente a los registros de segmento.

En la instruccin:

		jmp $		; Terminado

el smbolo "$"  se puede traducir como "aqu";  la instruccin lo que hace 
es detener  la ejecucin del programa,  ya  que la instruccin es un salto 
incondicional a su propia direccin.  El smbolo "$", como puede verse, es
un marcador genrico que es  interpretado  como la direccin del inicio de 
la lnea donde se encuentra.

Las instrucciones:

	org 510			; Hacer el fichero de 512 bytes de tamao
	dw 0AA55h		; Agregar la signatura de arranque

escriben  en  el  desplazamiento 5 10 del sector la signatura de sector de 
arranque vlido 0AA55h.

Otro hecho notable es que este programa no declara  una pila (stack) ni un 
segmento de datos: slo se declara un segmento de cdigo para todo. Se usa
el modelo de memoria TINY.  Esta  configiguracin  corresponde  al formato
original de los ficheros  ejecutables  de Microsoft DOS: COM. Pero nuestro
archivo no tiene ese formato, ya que los .COM inician en la direccin 100h
(o 256), ya que cuando se monta un programa en memoria para correrlo,  DOS
agrega al programa un area de datos de 256  bytes conocida como Prefijo de
Segmento del Programa (PSP);  por eso los programas .COM ponen al comienzo
la instruccin "org 100h",  para  que el conteo de instrucciones inicie en
100h.  Pero  el  nuestro inicia en 0,  por lo que no podr compilarse como
archivo .COM sino como .EXE, como lo hemos venido haciendo.  Luego debemos
usar un editor hexadecimal para extraer del .EXE  generado los ltimos 512
(200h) bytes y guardarlo como extensin .BIN o .IMG.

Luego escribimos este fichero en el  sector 1 de un disquete usando alguna 
herramienta como rawrite, para DOS o Windows, o dd de Linux.  Escribiremos 
aqu nosotros mismos una utilidad para hacer esto, que no es difcil.
 
Luego  hay  que  colocar el disquete en la unidad de floppy y reiniciar el
sistema.


	*NOTA: MBR para NASM*
	Para  la  escritura de sectores de arranque lo ms conveniente es 
	usar NASM, que adems ofrece una versin para Linux:

		http://sourceforge.net/projects/nasm/

	A continuacin una plantilla para escribir MBRs con NASM:

	    ; ----------------------------------------------------------------
	    ; MBR.ASM
	    ; Salta y luego cuelga el sistema
	    ; ----------------------------------------------------------------

	    ; Hay que decirle al ensamblador que este es el desplazamiento 0.
	    ; Si no es el desplazamiento 0, lo ser despus del salto.

		    ORG 0

	            jmp 07C0h:start         ; Ir al segmento 07C0

	    start:            ; Actualizar los registros del segmento
	            mov ax, cs
	            mov ds, ax
	            mov es, ax

	    hang:                           ; Colgarse
	            jmp hang

	    times 510-($-$$) db 0
	    dw 0AA55h

		; para ensamblar con NASM:
		;	    nasm mbr.asm -o mbr.bin
		; autor: Daniel Marjamki (daniel.marjamaki@home.se)

	    ; ----------------------------------------------------------------


	Son pocas las diferencias respecto a la plantilla anterior:

		Se escribe [ORG 0] en vez de ORG 100
		Se escribe jmp 07C0h:start en vez de:
	  		db 0EAh 
  			dw OFFSET AfterData, 7C0h    ; Esto hace que estemos en 7C0:0
		Se escribe
	    		times 510-($-$$) db 0
	    		dw 0AA55h
		en vez de:
			org 510
			dw 0AA55h

	La instruccin "times 510-($-$$) db 0" equivale a:
		db 510-($-$$) dup (0)

	pone ceros desde su ubicacin hasta el desplazamiento 510.  Luego 
	se coloca en ese desplazamiento la signatura AA55. La instruccin 
	"times" de NASM equivale a "DUP" de TASM: dice al ensamblador que 
	ensamble una instruccin tantas veces como lo  indique;  pero  se 
	puede aplicar a intrucciones de cdigo:  DUP  slo es aplicable a 
	intrucciones de declaracin de datos.  El argumento para TIMES no 
	es una constante numrica sino una "expresin" numrica,  as que 
	pueden emplearse instrucciones como:
	
		buffer:   db 'hello, world' 
		times 64-$+buffer db ' ' 

	El smbolo "$" designa "aqu": indica el comienzo de la lnea que 
	contiene la expresin y permite el  clculo  de instrucciones que 
	involucran la direccin actual de una instruccin. "$$" indica el 
	comienzo de la seccin donde se encuentra la  instruccin actual: 
	se emplea ($-$$) para indicar la distancia entre el  comienzo  de 
	la instruccin actual y el comienzo de la seccin. 

	Otro hecho notable es que NASM no necesita el uso de un enlazador
	para generar ficheros binarios o ficheros con formato .COM.


Antes de probar el cdigo de arriba,  escribamos un programa para  leer y 
escribir archivos al comienzo de un  disquete. Esto nos permitir revisar 
los servicios de la interface int13 del BIOS.


Programacin de E/S de disco
----------------------------
IBM ha program  una interface para el manejo de discos que respetan las 
especificaciones ATA: la interrupcin INT 13h.

Para especificar las direcciones se emplean los siguientes registros:

	CH: 8  bits  bajos  de los 10 bits empleados para especificar el 
	    nmero de cilindro o pista.

	CL: 2 bits altos de  los 10 bits del nmero de cilindro o psta: 
	    se almacenan en los bits 6 y 7. Los bits 0-5 son  los 6 bits 
	    del nmero de sector.

	DH: Nmero de cabezal o lado. Slo se usan los bits 0-3.

Para  indicar  error,  la  int13 pone en cero la bandera CF y regresa el 
cdigo del error en el registro AH.

A continuacin algunos servicios de la INT 13h:

  RESTABLECER EL SISTEMA DE DISCO
      AH = 00h (servicio o nmero de funcin).
      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 despus de un error grave.

      Una operacin vlida pone en cero la bandera CF; un error activa CF 
      y regresa el cdigo de error en AH. 


  LEER ESTADO DEL DISCO
      AH = 01h (servicio o nmero de funcin).
      DL = No.  de  unidad  (80h-FFh para discos duros, 128-255 decimal; 
	   0-7Fh para u. de floppy).

      La operacin se usa para examinar el estado de las operaciones  de 
      disco ms recientes.  Regresa en AL el cdigo  de  estado,  que la 
      ltima operacin puso seguramente en AH.


  LEER SECTOR(ES)
      AH = 02h (servicio o nmero de funcin).
      AL = nmero 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 traduccin puede ser 
	   0-255).
      DL = No.  de  unidad (80h-FFh para discos duros,  128-255 decimal; 
	   0-7Fh para u. de floppy).
      ES:BX = direccin del buffer E/S.

	  Desde  una  unidad  de  disquete  hay que asegurarse de que un 
	  pedido  de  lectura  no  cruce  el  lmite  de  una pgina DMA 
	  (direccin alineada 64K).  Es altamente indeseable que el BIOS 
	  se  encargue  del  problema  por  t.  La  manera ms fcil de 
	  cuidarse de esto es simplemente asegurarse de que la direccin 
	  del buffer que usas est  siempre  alineada  sobre  un  lmite 
	  igual al tamao pedido. Si lees cuatro sectores de  512 bytes, 
	  hay que alinear el buffer sobre el lmite de 2KB.

      Ejemplo:
	  _sector	db 512 dup (?)		; buffer
	...
		mov	ah, 2			; peticin 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 (nmero de la funcin de escritura).

          El resto de los parmetros 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 PARMETROS DEL DISCO
          AH = 08h  (nmero  de la funcin para obener los parmetros de 
	       la unidad).
          DL = nmero de unidad (igual que para leer/esribir sectores).

          Esta  funcin  regresar con  CF=0 si  la unidad es vlida. Al 
	  parecer,  no todos los BIOS activan o desactivan correctamente 
	  el indicador CF. Cuando se intenta detectar el disco instalado, 
	  se debe chequear el nmero de unidades regresadas en DL, cuando 
	  se ha chequeado el primer disco con DL=80h.

          Esta funcin regresa el mximo de parmetros 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 mximo del cilindro (menor 
	  o igual a 1023).

          CL[0-5] el mximo nmero de sectores, ya que los nmeros de 
	  sectores son con base uno, este valor es tambin una cuenta de 
	  los sectores.

          DH regresa el mximo nmero de cabezales (0-255, una vez ms, 
	  el nmero de cabezales-1).

	  DL regresa el No. de unidades conectadas al controlador del 
	  disco.

	  ES:DI regresa, para disquetes, la direccin de una tabla de 
	  11 bytes con parmetros 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 parmetros del
		disco)

          Notas:
          Es comn excluir el ltimo cilindro de la informacin regresada 
	  por estas funciones. En los compatibles IBM PCs, este cilindro 
	  se reserva para diagnsticos del fabricante. Si se escribe un 
	  sistema operativo o una utilidad de particin, se podra dejar 
	  como una opcin al usuario incluir o no este cilindro en una 
	  particin. Recordar siempre que la utilidad debera hacer una 
	  lectura/escritura/verificacin del cilindro antes de intentar 
	  usarlo. 


  CHEQUEO DE INSTALACIN DE EXTENSIONES INT13
          AH = 41h
          DL = nmero 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 tambin regresa en CX informacin sobre las 
          subfunciones soportadas. 


  LECTURA EXTENDIDA DE SECTOR(ES) 
          AH = 42h
          DL = nmero 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                    Tamao del paquete (10h)
          BYTE                    Reservado (00h)
          WORD                    Conteo de sectores
          WORD                    Desplazamiento (offset) del buffer
          WORD                    Segmento del buffer
          QWORD                   64-bits con la direccin del bloque 
				  lgico 


  ESCRITURA EXTENDIDA DE SECTOR(ES)
          AH = 43h
          DL = nmero 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. 


  OBTENCIN DE PARMETROS EXTENDIDOS DE LA UNIDAD (EXTENDED GET DRIVE 
   PARAMETERS)
          AH = 48h
          DL = nmero de unidad (igual para lectura/escritura de sectores).
          DS:SI = buffer para la estructura de parmetros de la unidad.

          (Estructura):

          WORD                    Tamao del buffer, 1Ah, 1Eh or 42h, 
				  depende de la versin de las 
				  extensiones.
          WORD                    Indicadores (flags) de informacin
          DWORD                   # de cilindros fsicos
          DWORD                   # de cabezales fsicos
          DWORD                   # de sectores fsicos
          QWORD                   64-bits con el nmero total de 
				  sectores de la unidad.

         Notas:
          La  tabla  de  arriba  describe  los valores regresados por una 
	  llamada en la versin 1.0.

          Mayor informacin 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 cdigo INT13: MBRREST
------------------------------------
Con  esta  informacin  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 tamao 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 interrupcin 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 tambin el cdigo para obtener argumentos desde  la  lnea  de
rdenes y crear un respaldo del sector de arranque original.  El  programa 
slo 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 lnea de rdenes
; ------------------------------------------------------------
	mov	si, 80h
	lodsb			   ; obtener nmero de caracteres
	test	al, al		   ; el nmero 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 lnea
	je	no_file		   ; saltar si se lleg al final

	dec	si		   ; ajustar el puntero
	push	si		   ; salvar la direccin de la cadena
	; buscar el final de la cadena
next:	lodsb
	cmp	al, 13		   ; se alcanz el final de lnea?
	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 direcin 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		   ; tamao 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

	; Creacin 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 parmetro?

	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 tamao 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 	   ; direccin 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
	; slo 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 cambirsele 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 slo har un
respaldo del primer sector del disquete.

Esta herramienta no te funcionar correctamente desde Windows 2000, ya
que protege contra escritura en discos.



 - Anlisis de MBRREST - 
La primera observacin 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 cdigo.  Tampoco es necesario definir una pila:  los
ejecutables  con  formato  COM generan automticamente la pila.  Como estos 
archivos usan un segmento para cdigo y datos,  su  tamao est restringido
a 64KB. 

Cuando DOS monta el programa, pone en DS y CS la direccin del PSP (Prefijo 
de Segmento el Programa). El PSP es una pequea base de datos de 256 (100h) 
bytes que construye DOS en el lmite de un prrafo (16 bytes) en la memoria 
interna disponible cuando carga  un  programa  en  memoria,  inmediatamente 
despus se cargar el programa  mismo.  El  PSP  tambin  forma  parte  del 
segmento nico de 64 KB.

Como el programa comienza a ejecutarse inmediatamente despus del PSP, debe
indicrsele al ensamblador que genere el cdigo a partir del desplazamiento
100h (256).  Esto se le indica con la directiva ORG, inmediatamente despus
de iniciar el segmento de cdigo con .code o con la directiva SEGMENT:

	.code
	ORG	100h

Los registros CS y DS ya tienen la direccin apropiada,  as que no hay que
iniciarlos como se haca con los archivos .EXE.

Nuestro programa,  despus de mostrar un mensaje con el copyright,  obtiene
un puntero a los argumentos que se la pasan al  programa cuando se  ejecuta
desde DOS.  El PSP mantiene en 80h:FFh,  el bufer por omisin del DTA (Data
Tranfer  Disk:  rea  de  transferencia  a  disco);  ah  DOS pone el texto 
completo  que escribe el usuario despus de la peticin del programa por su 
nombre: se tratara de los parmetros que se le pasan al programa.

La instruccin:
; ------------------------------------------------------------
; Obtener el nombre del archivo pasado en la lnea de rdenes
; ------------------------------------------------------------
	mov	si, 80h

pone en SI la direccin del buffer DTA.

El primer byte de ese buffer contiene el nmero de caracteres que tecle el
usuario despus del nombre del programa. En el programa obtenemos es nmero
con la instruccin:

	lodsb			   ; obtener nmero de caracteres

Luego verificamos si se escribi algo despus del nombre:

	test	al, al		   ; el nmero es cero?
	je	no_file		   ; si es cero saltar

si no se escribi nada,  CL tendr cero y se pasar el control dnde indica
la  etiqueta  "no_file".  Si  se  escribi  algo,  se  procede saltarse los 
espacios.  Despus  del  nombre  se  debe  escribir uno o ms espacios para 
separarlo de los parmetros, y deben saltarse los bytes con esos espacios:

	; 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 lnea
	je	no_file		   ; saltar si se lleg al final

Esta  rutina va colocando en AL el caracter a que  apunta SI,  lo  cual  es 
hecho por la instruccin LODSB; luego se revisa si ese caracter es 20H,  el 
valor  ASCII del espacio,  y si lo es vuelve a ejecutarse LODSB y se repite 
el ciclo hasta encontrar un caracter  distinto a 20h,  el espacio.  Despus 
hay que revisar si slo se pasaron espacios.  El  ltimo  caracter que debe 
haber  en el buffer es 13 o 0Dh,  que es el equivalente ASCII para el salto 
de linea generado al pulsar la  tecla  ENTER.  As que se este es el ltimo 
caracter despus  de  la  serie  de  espacios,  entonces  no  se  introdujo 
parmetros y se pasa el control a la rutina en "no_file".

Luego decrementamos SI en uno para que apunte al primer caracter.  Salvamos 
en la pila la direccin que da inicio a los argumentos pasados.

	dec	si		   ; ajustar el puntero
	push	si		   ; salvar la direccin de la cadena

A continuacin buscamos el timo caracter, que debe ser 13 o 0Dh:

	; buscar el final de la cadena
next:	lodsb
	cmp	al, 13		   ; se alcanz el final de lnea?
	jne	next		   ; revisar siguiente si no se alcanz?

Ya localizado, lo reemplazamos por cero, para tener una cadena terminada en
cero, y recuperamos en SI el puntero al inicio de la cadena:

	; 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 direcin de la cadena
	jmp	_with_file	   ; proceder a hacer el respaldo

Obsrvese  la  2da. instruccin.  Incluye un operador que indica el tipo de 
puntero,  en este caso un puntero a byte:  "ptr"  es un operador que se usa
para indicar el tamao de un dato inmediato a poner  en  una  direccin  de
memoria. Su formato es:

	tipo	ptr	direccin_de_memoria

"tipo"  es  una  indicacin  del  tipo de dato,  que puede ser: byte, word, 
dword, qword.

Si  no se  pas  parmetros, se pone cero donde apunta SI, lo que se  usar 
luego para revisar si el usuario llev a cabo esta accin:

no_file:
	dec	si
	mov	byte ptr [si], 0   ; SI apunta a cero

Luego comenzamos las rutinas que usan la int 13h para hacer un respaldo del 
sector de arranque actual, por si acaso.  Primero  preparamos el sistema de 
disco con el servicio 0 e la int13:

_with_file:
	mov     ax, 0              ; reestablecer sistema de disco
	mov     dl, 0		   ; 0 para floppy, cambiar a 80h para
	int     13h		   ; discos duros

Ahora  verificamos  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
	call	_szDisplay
	jmp	close_file

El nmero de sectores por  pista,  de pistas por lados,  y de  lados,  son 
valores bien conocidos para los disquetes con capacidad de 1.44 MB:

	sectores por pista: 18
	pistas por lado:    80
	lados:		     2


De  inmediato  leemos  el  primer  sector del disco en el buffer usando el 
servicio 2 ede la int13. Esto lo hacemos cuatro veces. Los comentarios son 
bien descriptivos:

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		   ; tamao 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 (80h: disco duro)
	mov	ch, 0		   ; pista 0
	mov     cl, 1              ; sector 1
	lea     bx, buffer
	int     13h 
	dec     bp  
	jnz     read

Aqu hemos agregado una rutina que limpia el buffer: _ZeroMemory:

	_ZeroMemory:
		push	di
		mov	al, 0
		rep stosb
		pop	di
		ret

La funcin recibe en CX el tamao del buffer a limpiar y en DI la direccin
del buffer.  Lo que hace la subrutina es escribir  'n'  cantidad de ceros a
partir de la direccin sealada por DI.

 - Operaciones con archivos en DOS (I) -
Ya con el buffer lleno, procedemos a escribir estos datos en un disco. Antes 
hay  que crear  el archivo donde pondremos los datos del sector de arranque, 
que ahora deben estar en el buffer.  Para crear un fichero nuevo llamamos al 
servicio 3Ch de la int21 de DOS:

	mov     ax, 3C00h          ; crear el fichero de respaldo
	mov     cx, 0		   ; atributo del archivo 0 = normal	
	lea     dx, bu_file 	   ; nombre del archivo
	int     21h
	jc	error_writing	   ; saltar si hubo error
	mov     bx, ax             ; mover el handle del fichero a BX

El atributo del archivo a crear se pasa en CX:

	00: normal
	01: slo lectura
	02: oculto
	04: sistema DOS

Si hay en error al crear, se activa la bandera de carro CF.  La instruccin
"JC"  revisa  esa  bandera y si est activa pasa el control a la  direccin
indicada por la etiqueta que le sigue. Si la operacin tiene exito devuelve
en AX el handle del fichero creado,  el cual se debe usar para  operaciones
de lectura/escritura sobre el fichero y para cerrarlo luego.

A continuacin procedemos a escribir los datos en el fichero creado, usando
el servicio 40h de la int21 de DOS:

	; 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

Como puede observarse,  BX tiene el handle del fichero,  CX la cantidad de 
datos a mover, y DX la direccin donde estn los datos. Nuevamente, si hay 
error se activa la bandera de carro CF.

Si no hubo problemas,  se cierra el handle del fichero usando  el servicio
3Eh de la int21; no se olvide que an BX tiene el handle:

	; Cierre del fichero de respaldo

	mov     ah, 3Eh           ; cerrar el archivo creado para respaldo
	int     21h 
	jmp     restore

Si hubo error en la creacin o lectura del archivo,  desplegamos  un aviso
y salimos a DOS usando la int20 de DOS:

error_writing:
	lea	si, error_w
no_name:
	call	_szDisplay
	int	20h

Pero si todo va bien,  revisamos si se ha pasado el nombre de un  archivo
como parmetro; si no se  hizo, se avisar que no se pas el nombre de un 
archivo para copiar en el 1er. sector del disquete, no se copiar nada en 
l pero s se conservar el que haba ya en el disquete  (recurdese  que 
al comienzo se hace un respaldo):

restore:
	; Se pas nombre de archivo como parmetro?	

	lodsb
	test	al, al
	jne	@00

	; Si no se pas nombre, avisar y salir
	lea	si, warning
	jmp	no_name	

Para la revisin, basta revisar si SI apunta a cero, lo que indicara que 
no se ha pasado ningn nombre. Si se pas un nombre, se procede a abrirlo 
en modo de slo lectura usando el servicio 3Dh de la int21 de DOS:

@00:	push	si
	lea     si, msg2     	   ; desplegar el mensaje de aviso
	call	_szDisplay
	pop	si

	dec	si
	mov     ax, 3D00h          ; abrir fichero indicado para lectura
	mov     dx, si		   ; nombre del archivo
	int     21h
	jc      error              ; error abriendo el fichero?
	mov     bx, ax             ; mover el handle del fichero a BX


Verificamos si el archivo cabe en un disquete de 1.44MB.  Para obtener el
tamao del  archivo,  usamos el servicio 42h de la int 21h,  que mueve el 
puntero del archivo al sitio indicado:

	mov	ax, 4202h
	mov	cx, 0
	mov	dx, cx
	int	21h
	jc      error              ; error abriendo el fichero?

La  direccin  para  colocar  el  puntero se pone  en CX:DX.  En AL debe 
colocarse desde donde debe tomarse la direccin:

	0	contar desde el inicio del fichero
	1	contar desde la direccin actual del puntero
	2	contar desde el final del fichero

El servicio regresa en DX:AX la nueva direccin. Por eso, si colocamos el
puntero al final del fichero, obtendremos en DX:AX la nueva direccin del
puntero, que en este cso coincidir con el tamao del fichero.

Luego  verificamos si el fichero cabe en una  unidad de  floppy.  Primero 
comprobamos si es menor que  160000h =  1.441.792 bytes

	cmp	dx, 016h
	jl	good_for_floppy1

Si lo es, puede caber, sino se cierra el fichero y salimos del programa:

bad_for_floppy:
	lea	si, msg3
	call	_szDisplay
	jmp	close_file	   ; cerrar el fichero

Luego vemos si es menor que 150000h = 1.441.792;  si no lo es, revisamos
si la parte baja es mayor F900h = 63744 bytes (1.44MB = 0015F900h)

good_for_floppy1:
	cmp	dx, 015h
	jl	good_for_floppy2
	cmp	ax, 0F900h
	jg	bad_for_floppy

Si todo ha ido bien, obtenemos el nmero de sectores que vamos a copiar:

good_for_floppy2:
	mov	cx, 200h
	div	cx
	mov	uSector, ax
	or	dx, dx
	je	rounded

	inc	word ptr [uSector]

Simplemente dividimos el valor DX:AX entre 200h, el nmerode bytes en un
sector. Si hay resto, es colocado en DX y agregamos 1 al valor contenido
en la variable donde guardamos el nmero de sectores: uSector.


	*NOTA: la instruccin DIV*
	La divisin la hacemos usando la instruccin DIV.  El fomato  de
	esta instruccin es:

	DIV	reg/memoria

	Acepta un operando, que puede ser un registro o un  operador  de
	memoria. Ese operando ser el divisor.

	La  instruccin se usa para dividir enteros  sin  signo.  Divide 
	entre un valor tipo word y uno tipo byte;  uno tipo dword y otro 
	word; uno qword y otro dword.  El operando  a la derecha  de  la
	instruccin designa eldivisor;  para  el  dividendo  se  usa AX, 
	DX:AX o EDX:EAX, dependiendo del tamao del divisor. Es decir:

	 para dividir word entre byte:	el dividendo en AX
	 para dividir dword entre word: el dividendo en DX:AX
	 para dividir qword entre dword: el dividendo en EDX:EAX

	Dependiendo del tamao de los operandos, la operacin devuelve en

	 AL el cociente y el residuo en AH para word/byte;
	 AX el cociente y el residuo en DX para dword/word;
	 EAX el cociente y el residuo en EDX para qword/dword;

	Ejemplos:

	b_dat		DB	?
	w_dat		DW	?
	d_dat		DD	?

	operacin   divisor   dividendo   cociente   residuo
	  DIV CL     byte        AX          AL         AH
	  DIV BX     word       DX:AX        AX         DX
          DIV EBX    dword     EDX:EAX       EAX        EDX

	DIV b_dat    byte        AX          AL         AH	
	DIV w_dat    word       DX:AX        AX         DX
	DIV d_DAT    dword     EDX:EAX       EAX        EDX


Una vez  que  tenemos  el nmero de  sectores, los copiamos en el disco.
Primero debemos reponer el puntero del fichero al comienzo del mismo.

rounded:
	mov	ax, 4200h	   ; AL = 0: desde el comienzo
	mov	cx, 0		   ; poner en 
	mov	dx, cx		   ; 0000:0000
	int	21h
	jc      error              ; error abriendo el fichero?

El modo de apertura del archivo debe ser indicado en AL.  Si se abri el 
archivo sin problemas, entonces AX = 0.  Como vamos a comenzar  copiando
el sector 1, de la pista o cilindro 0, del cabezal o  lado 0,  iniciamos
las siguientes variables con estos valores:

	mov	track, al
	mov	head, al
	inc	ax
	mov	sector, al

Luego  leemos el archivo  sector  por sector, iniciando la lectura en el
sector mencionado. Antes de leer cada sector, limpiamos el buffer:

get_next_sector:
	lea	di, buffer
	mov	cx, 512
	call	_ZeroMemory

La funcin  3Fh  de la  int 21h lee una cantidad indicada de bytes de un
archivo iniciando en el  lugar donde est el puntero de archivo y coloca 
lo ledo en el buffer cuya direccin est en DX:

	mov     ah, 3Fh            ; leer el fichero en el buffer
	mov     cx, 512
	lea     dx, buffer
	int     21h
	jnc	write_sector	   ; hubo error?

	lea	si, error_r	   ; si hubo error,
	call    _szDisplay	   ; avisar y
	jmp	close_file	   ; cerrar el fichero

Si  hay  error,  se  activa la bandera CF,  lo que har que se cierre el 
archivo y se salga del programa.

Si todo va bien,  podremos escribir el sector.  Primero restablecemos la 
unidad:

write_sector:
	push	ax

	; Escritura del fichero en el disco

	mov     ax, ax             ; restablecer el sistema de disco
	mov     dl, 0		   ; para disquete: mov dl, 0
	int     13h

Luego  procedemos a escribir el sector,  salvando el registro BX,  donde 
se halla el handle del fichero:

	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 	   ; direccin del buffer a escribir
	int     13h
	dec     bp
	jnz     write

Usamos el servicio 3 de la int 13h para escribir los datos al disco.

Recuperamos el handle del archivo, que necesitaremos para cerrarlo:

	pop	bx

Si se llega al sector 18 (sectors_per_track), se escribe en el siguiente 
track y se comienza de 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 slo tiene 2 
lados:

	cmp	side, 3
	je	close_file

Se  revisa si ya se leyeron todos los sectores,  en cuyo caso el valor en
uSector sera igual a cero. Si no es este el caso,  se copia el siguiente
sector del archivo.

count_sector:
	dec	uSector		   ; Disminuir conteo de sectores a copiar
	jne	get_next_sector	   ; Si no se lleg a cero, copiar el siguiente


Si  ya lemos todo el archivo  y lo hemos copiado a los primeros sectores
del disco, cerramos el fichero y salimos

close_file:
	mov     ah, 3Eh            ; cerrar el fichero
	int     21h

	int     20h                ; regresar a DOS ...


	mov     ah, 3Fh            ; leer el fichero en el buffer
	mov     cx, 512		   ; leer 512 bytes y
	lea     dx, Buffer  	   ; ponerlos en esta direccin
	int     21h

Ahora  que hemos diseado nuestra herramienta,  procedemos  a disear un 
pequeo sector de arranque. Antes un poco de informacin.


Cdigo del MBR (Master Boot Record: Sector Maestro de Arranque)
===============================================================
Como ya hemos dicho, el sector de arranque de los discos duros, conocido 
como el MBR - Master Boot Record, es el sector CHS sector 0/0/1 o LBA 0. 
Este  sector es cargado y ejecutado por  el BIOS cuando se arranca desde 
el dico duro.  Contiene  un p equeo  programa  de arranque  maestro que 
realizar varias tareas.  El MBR es equivalente al sector de arranque de 
los diskettes,  pero hay diferencias entre ambos,  ya que el disquete no 
soporta particiones.

Un MBR tiene tres partes esenciales:
 
	 El  cdigo  que  carga  un sector de arranque desde una de las 
	  cuatro perticiones primarias.

	 La tabla de particiones en el desplazamiento  446,  que  tiene 
	  cuatro entradas de
	  16 bytes, una paracada particin.

	 Valores mgicos: 55h en el desplazamiento 510, 0AAh en el 511.

El sector de arranque de un disquete no  tiene  tabla  de  particin.  A 
continuacin  las direcciones donde se ubican las partes principales  de 
un MBR:

Desplazamiento	Descripcin		Tamao

000h		Cdigo ejecutable 
		(arranque)		446 Bytes

1BEh		1ra entrada de la 
		tabla de particin	16 Bytes

1CEh		2da entrada de la 
		tabla de particin	16 Bytes

1DEh		3ra entrada de la 
		tabla de particin	16 Bytes

1EEh		4ta entrada de la 
		tabla de particin	16 Bytes

1FEh		Marcador "AAh 55h"	2 Bytes



El proceso de arranque es ms o menos este:

1. El BIOS pone en el registro DL del procesador el nmero de la unidad 
   de arranque: 0 para    una unidad de floppy A,  u  80h para el disco
   duro C. 

2. El  BIOS lee el sector CHS 0/0/1  del primer dispositivo de arranque 
   disponible, en este caso sera el disco duro.

3. El sector es ledo y colocado en una direccin fija de la  memoria - 
   0000:7C00, a la cual se le transfiere el control.

4. El BIOS chequea el sector de arranque en busca de la signatura:  55h 
   en el desplazamiento 510 y 0AAh en el 511.

5. El programa de arranque se reubicar  a s mismo en la memoria baja,
   para permitir que el sector de arranque  de  la particin activa sea 
   cargado tambin en 0000:7C00h.

6. El  programa maestro de arranque salta a la siguiente instruccin en 
   la nueva direccin - generalmente 0000:06nn o 0060:nnnn.

7. El  programa maestro de arranque chequear las cuatro entradas de la 
   "Tabla de Particin" en busca de una particin marcada como "activa" 
   buscando un valor 80h en la entrada propicia de la tabla.

8. Si  ninguna  particin  est  marcada  como "activa", el programa de
   arranque  (dependiendo de quien lo escribi)  informar  al  usuario 
   sobre  esto  o ejecutar el ROM BASIC -  llamando a  la  INT18,  que 
   generalmente reinicia  desde otra  unidad.  El  master  boot  record 
   instalado por FDISK de  DOS requerir que el campo "activo" sea 00 u 
   80h para  unidades de disco,  cualquier  otro  valor  ocacionar  un 
   mensaje "Invalid partitioning table". 

9. El  primer  sector  CHS  de  la  particin  "activa" ser cargado en 
   0000:7C00, como el MBR. Luego se le transfiere ah el control con un 
   JMP a 0000:7C00.

La  misin  del  MBR es  encontrar y cargar en la memoria el ncleo del 
sistema,  o un  segundo estadio del cargador;  estas operaciones pueden 
realizarse de alguna de las tres siguientes maneras: 

	 Asumir  que  el  ncleo  del sistema o el segundo estadio del 
	  cargador estn cargados  en espacios contiguos (el  disco  no 
	  tiene sistema de archivos)
 
	 Encontrar  cuales sectores del disco contienen el ncleo  del
	  sistema  o  el segundo estadio del cargador,  y escribir esta 
	  lista de  sectores en el cdigo del primer  estadio (el disco
	  puede o no o tener sistema de archivos)

	 Usar el sistema de archivos presente en el disco

El programa de arranque debe obtener el valor de sectores por pista del 
disco. Las particiones FAT pueden obtenerla de una tabla que DOS  tiene 
en  el  sector  de  arrranque:  el  BPB  (BIOS parameter block).  Otros
sistemas de archivos,  asumen un valor,  como 18 sectores por pista,  o 
usan  prueba  directa: se cargan sectores usando la int13 y se practica 
una bsqueda binaria hasta encontrar el valor sectores/track.  


Unas palabras sobre las particiones
-----------------------------------
Como  algunas  personas a veces quieren tener en su mquina ms  de  un 
sistema operativo,  IBM decidi implementar particionamiento del disco. 
Para estos fines,  reserv  una  pequea  area  en el primer sector del 
disco: el sector CHS 0/0/1 o sector LBA 0, para una Tabla de Particin.

Esa  tabla  tiene cuatro entradas;  cada una especifica las direcciones 
del  comienzo  y  del  final  de  una particin:  uno de los dos campos 
espcifica  el  comienzo,  mientras que el otro especifica el nmero de 
sectores  consecutivos en las particiones. Por ejemplo, para una unidad 
de 1 GB:

          520 Cilindros
          64  Cabezales
          63  Sectores

Por  compatibilidad  con  la  INT13, muchas unidades ATA-2 tendrn una 
traduccin  CHS  a LBA donde los sectores por pista  (SPT: Sectors Per 
Track), no excedern los 63,  incluso  si todas las unidades  permiten 
que el mximo sea 255.

Los 16 bytes de una entrada de la tabla de particin se usan as:

    +--- El bit 7 es la bandera de particin activa, los bits 6-0 estn
    |    en cero.
    |    +--- Comienzo de CHS en el formato de una llamada a INT13.
    |    |
    |    |      +--- Byte de tipo de particin.
    |    |      |
    |    |      |    +--- Fin de CHS en el formato de una llamada a INT13.
    |    |      |    |
    |    |      |    |        +-- Comienzo de LBA.
    |    |      |    |        |
    |    |      |    |        |       +-- Tamao en sectores.
    |    |      |    |        |       |
    v <--+--->  v <--+-->     v       v

   0  1  2  3  4  5  6  7  8 9 A B  C D E F
   DH DL CH CL TB DL CH CL LBA..... SIZE....

   80 01 01 00 06 0e be 94 3e000000 0c610900  1ra entrada

   00 00 81 95 05 0e fe 7d 4a610900 724e0300  2da entrada

   00 00 00 00 00 00 00 00 00000000 00000000  3ra entrada

   00 00 00 00 00 00 00 00 00000000 00000000  4ta entrada

Los bytes 0-3 son usados por el pequeo programa en el MBR para  ubicar 
el primer sector de una particin activa en la memoria.

El  byte  cero indica si la particin  es  inicializable:  su valor  es  
devuelto en DH.  El byte 1 indica el cabezal o lado (base 0):  su valor 
es devuelto en DL.  El  byte  2 contiene 8 bits bajos de que indican el 
nmero de cilindro o pista (base 0). El byte 4 se divide en dos partes: 
sus 6 bits bajos indican el nmero de sector donde inicia la  particin 
(base 1) y los 2  bits altos corresponden a los dos bits altos  de  del 
nmero de cilindro (el nmero de cilindro  se indica por un dato de  10 
bits, 8 bajos los pone CH, y dos altos los pone los  dos bits altos  de 
CL; as que el nmero de pistas puede ir de 0 a 2^10 = XXXX)
 
El byte 4 indica el tipo de particin. En este caso es 6: DOS FAT.


		Lista de algunos tipos de particiones
 -----------------------------------------------------------
| Valor	|  Descripcin
 -----------------------------------------------------------
| 00h	|  Desconocida o nada
 -----------------------------------------------------------
| 01h	|  FAT de 12-bit 
 -----------------------------------------------------------
| 04h	|  FAT de 16-bit (Particin menor que 32MB)
 -----------------------------------------------------------
| 05h	|  Particin Extendida MS-DOS
 -----------------------------------------------------------
| 06h	|  FAT de 16-bit (Particin mayor que 332MB)
 -----------------------------------------------------------
| 0Bh	|  FAT de 32-bit (Particin de hasta 2048GB)
 -----------------------------------------------------------
| 0Ch	|  Lo mismo que 0BH, pero usa extensiones LBA1 13h
 -----------------------------------------------------------
| 0Eh	|  Lo mismo que 06H, pero usa extensiones LBA1 13h
 -----------------------------------------------------------
| 0Fh	|  Lo mismo que 05H, pero usa extensiones LBA1 13h
 -----------------------------------------------------------
| 80h	|  Linux
 -----------------------------------------------------------
| 81h	|  Linux -Minix
 -----------------------------------------------------------


Como puede verse, la particin comienza en  CHS 0H, 1H, 1H (LBA 3EH)  y 
termina en CHS 294H, EH, 3EH con un tamao de 9610CH sectores. El valor 
en este campo de 32 bits se calcula de la manera estndar:

  Inicio = ((InicioC * HeadsPerCylinder) + InicioH) * 
		SectorsPerTrack) + InicioS - 1

La segunda particin es del tipo 5:  particin extendida;  comienza en 
CHS 295H, 0H, 1H (LBA 9614AH) y termina en CHS  37DH,  EH,  3EH con un 
tamao  de  34E72H  sectores.  Este campo tambin es de 32-bits,  para 
decir cuntos sectores usa la particin.  Puede  ser  usado calculando 
dos algorritmos mayores:

  Cuenta = (((FinC - InicioC) * HeadsPerCylinder) + (FinH - InicioH)) * 
		     + SectorsPerTrack + (FinS - InicioS)

	  C = Cilindro
	  H = Cabezal [Head]
	  Track = Pista
	  HeadsPerCylinder = Cabezal por Cilindro
	  SectorsPerTrack = Sectores por Pista

En  el  campo  de  arriba  no se resta 1 al final,  porque queremos el 
"contador de sectores", y no la direccin LBA con base cero del ltimo 
sector. 

Hay otro mtodo tambin, la idea es la misma, pero calcula el  "ltimo 
sector LBA" y substrae el despus el campo "Inicio" [start]:

  Cuenta = (((FinC * HeadsPerCylinder) + FinH) * 
		SectorsPerTrack + FinS - 1) - Inicio


Las entradas de la tercera y de la cuarta tabla no se estn usando.

A continuacin una tabla con los detalles de una tabla de particin:

 -------------------------------------------------
|desplazamiento	Descripcin		Tamao
 -------------------------------------------------
|  00h		Estado (00h=Inactive, 	1 byte
|		80h=Active)
 -------------------------------------------------
|  01h		Comienzo de la
|		Particin - Cabezal	1 byte
 -------------------------------------------------
|  02h		Comienzo de la
|		Particin - 		1 Word
|		Cilindro/Sector 	(2 bytes)
 -------------------------------------------------
|  04h		Tipo de
|		Particin		1 Byte
 -------------------------------------------------
|  05h		Fin de la
|		Particin - Cabezal	1 byte
 -------------------------------------------------
|  06h		Fin de la
|		Particin - Cabezal	1 Word
|		Cilindro/Sector 	(2 bytes)
 -------------------------------------------------
|  08h		Nmero de sectores
|		entre el MBR y el	1 DWord
|		Primer Sector en la	(4 bytes)
|		Particin
 -------------------------------------------------
|  0Ch		Nmero de sectores	1 DWord
|		en la Particin
 -------------------------------------------------



Escribir un sector de arranque
------------------------------
Para  terminar,  hagamos el ejercicio de escribir un pequeo sector de 
arranque  para la unidad de floppy.  Por supuesto,  no tendr tabla de 
particiones lo que lo har ms  sencillo. Usaremos  la  plantilla  que 
expusimos arriba que emplea NASM:


; ---------------------------------------------------------------------------
    ; -----------------------------------------------------------------
    ; boots.ASM
    ; Pequeo bootstrap
    ; Carga un programa del disco y le pasa el control
    ; Versin: n u MiT_o r
    ; -----------------------------------------------------------------

    ; ----------------------------------------------------------------
    ; Hay que decirle al ensamblador que este es el desplazamiento 0.
    ; Si no es el desplazamiento 0, lo ser despus del salto.
    ; ----------------------------------------------------------------

	    ORG 0

            jmp 07C0h:start     ; Ir al segmento 07C0
     start: ; -------------------------------------
            ; Actualizar los registros de segmento
            ; -------------------------------------
	    cli			; Deshabilitar las interrupciones
            mov ax, 07C0h	; Ajustar los registros del
            mov ds, ax		; segmento de datos
            mov es, ax
            ; -------------------
            ; Establecer la pila
            ; -------------------
	    mov ax, 9000h	; Poner la pila en 90000h
	    mov ss, ax		; SS = 9000h
	    mov sp, 0FFF0h	; SP = 0FFF0h => Stack = 90000h
	    sti			; habilitar interrupciones
            ; --------------------------------
            ; Desplegar mensaje de bienvenida
            ; --------------------------------
            lea si, [__msg]
            call _szDisplay_
            ; --------------------------------
            ; Restablecer la unidad de floppy
            ; --------------------------------
     reset:
	    mov cx, 0
	    mov ax, cx       	; reestablecer sistema de disco
	    mov dl, al		; 0 para floppy, cambiar a 80h para discos duros
	    int 13h
            ; ----------------------------------
            ; Subir el 2do. sector a la memoria
            ; ----------------------------------
     read:
            mov bx, 200h        ; desplazamiento de la segunda etapa

            mov ah, 2           ; Cargar los datos del disco a ES:BX
            mov al, 5           ; Cargar 3 sectores
            mov ch, 0           ; Cilindros=0
            mov cl, 2           ; Sector=2
            mov dh, 0           ; Cabezal=0
            mov dl, 0           ; Unidad=0
            int 13h             ; Leer!

	    jnc ok_load_setup	; si no hubo problemas, se contina

	    lea  si, [_err_]	; despliega mensaje de error
            call _szDisplay_
	    mov  ah, 16
	    int  16h
	    jmp  read

ok_load_setup:
            lea si, [__msg_]	; despliega mensaje de aviso
            call _szDisplay_
	    mov	    ah, 16
	    int     16h

	    DB 0xEA		; jump to sector 02
	    DW 0x7E00		; offset 
	    DW 0x0000		; segment 
 
; ====================================================================

        _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

; --------------------------------------------------------------------
__msg  db " --------------------------------------", 13, 10
       db "Prueba de dise", 0A4h, "o de bootstrap", 13, 10
       db "Por  n u MiT_o r", 13, 10
       db "----------------------------------------", 0

__msg_ db 13, 10, "Sector 2 copiado en 07C0h:0200h", 13, 10
       db "Pulsa una tecla para continuar....", 13, 10, 0
_err_  db 13, 10, "Error al leer desde el disco", 13, 10, 0

    times 510-($-$$) db 0
    dw 0AA55h
; ---------------------------------------------------------------------------


Este es el programa que ser cargado:

; ---------------------------------------------------------------------------


; -------------------------------------
; console.asm
; Pequeo intrprete de rdenes
; (C) n u MiT_o r 2002
; -------------------------------------

; -------------------------------------
; Acepta tres rdenes:
;	help: imprime lista de rdenes
;	clean: limpia la pantalla
;	exit: reinicia del sistema
; -------------------------------------

_init:
	; Despliega de bienvenida
	lea	si, [msg1]
	call	_szDisplay
_loop:
	; Despliega puntero
	lea	si, [puntero]
	call	_szDisplay

	; Obtiene la orden
	lea	di, [command]
	call	_get_command
_is_clean:
	; Es la orden clean?
	lea	si, [_clean_]
	call	_compare
	test	ax, ax
	je	_is_exit
	; Limpiar el monitor
	call	clean_
	jmp	_loop	
_is_exit:
	; Es la orden "exit"
	lea	si, [_exit_]
	call	_compare
	test	ax, ax
	je	_is_help
	; reiniciar el sistema
_reboot:
        db 	0EAh        ; Cdigo de operacin para JMP
        dw 	0000h       ; Saltar a FFFF:0000h, que reinicia
        dw 	0FFFFh      ; el sistema
_is_help:
	; Es la orden "help"
	lea	si, [_help_]
	call	_compare
	test	ax, ax
	je	_no_order
_help:
	lea	si, [hmsg]
	call	_szDisplay
	jmp	_loop	
	
_no_order:
	lea	si, [msg2]
	call	_szDisplay
	jmp	_loop

; ====================================================================
	_szDisplay:
		push	si
                __print_string:
			lodsb
			test	al, al
                        jz      __exit_szDisplay

			call	__display_char

                        jmp     __print_string 
                __exit_szDisplay:
		pop	si
			ret


	__display_char:
		mov	bx, 000Fh                                                   
		mov	ah, 0Eh                                                     
		int	10h
		ret

; --------------------------------------------------------------------
	_get_command:
		push	di
		mov	cx, 12
	_loop_:
		mov	ah, 10h
		int	16h
	filt_extended_function_keys:
		test	al, al
		je _loop_
		cmp	al, 0E0h
		je _loop_
	is_enter_key:
		cmp	al, 0Dh
		je _exit_get_command
		dec	cx
		test	cx, cx
		je _excess
	get_character:
		stosb
		call	__display_char
		jmp _loop_
	_exit_get_command:
		xor	al, al
		stosb
		pop	di
		ret

	_excess:
		lea	si, [msg3]
		call	_szDisplay
		mov	cx, 12
		pop	di
		push	di
		jmp _loop_
	
; --------------------------------------------------------------------
	_compare:
		push	si
		push	di
	get_string_lenght:		
		xchg	di, si
		call	_strlen
		xchg	si, di
	_compare_strings:
		repe cmpsb
		test	cx, cx
		jne	_not_equals
		mov	ax, 1
		jmp	_exit_compare
	_not_equals:
		mov	ax, 0
	_exit_compare:
		pop	di
		pop	si
		ret	


	_strlen:
		push	di
		mov	al, 0
		mov	cx, -1	; cx = -1 = FFFFh = 65535 = infinito
		repne scasb
		neg	cx
		dec	cx
		dec	cx
		pop	di
		ret

; --------------------------------------------------------------------
	clean_:
		mov	dx, 0
		call	set_cursor
		mov	cx, 80*25
	_print:
		mov	al, 32	; 32 = 20h = espacio
		call	__display_char
		loop	_print

		mov	dx, 0
		call	set_cursor
		ret

	set_cursor:
		mov	ah, 2
		int	10h
		ret

; ----------------------------------------------------------------------------------

	msg1	db	"Int",82h,"rprete de ",0A2h,"rdenes", 10, 13
		db	"Escribe 'help' para ver las opciones", 10, 13, 0
	msg2	db	7, 10, 13, "No es una orden del programa!", 10, 13, 0
	msg3	db	7, 10, 13, "Introdujo m",0A0h,"s de 12 caracteres", 10, 13
	puntero	db	10, 13, "> ", 0
	hmsg	db	10, 13, "Ordenes disponibles en este shell:", 10, 13
		db	       "       ", 0FEh," help:  despliega este mensaje", 10, 13
		db	       "       ", 0FEh," clear: limpia el monitor", 10, 13
		db	       "       ", 0FEh," exit:  reinicia el sistema", 10, 13, 0

	_help_	db	"help", 0
	_clean_	db	"clean", 0
	_exit_	db	"exit", 0

	command:
		times 12 db 0

; ----------------------------------------------------------------------------------


El siguiente programa crea un archivo imagen que contiene el bootstrap 
y el pequeo programa:

; ---------------------------------------------------------------------------
    ; ---------------------------------------------------
    ; IMAGE.ASM
    ; Disk image
    ; ---------------------------------------------------

    %include 'boot.asm'
    %include 'console.asm'

	; ---------------------------------
	; Todo se compila con
	;	nasm image.asm -o image.img
	; ----------------------------------

; ---------------------------------------------------------------------------


Al compilar el programa, se genera un archivo llamado image.img.  Para
ejecutarlo, hay que copiarlo en un disquete.  Se  puede  emplear  para 
ello la herramienta que escribimos: MBRREST; pero si lo deseas, puedes
usar RAWRITE: http://uranus.it.swin.edu.au/~jn/linux/rawwrite.htm.

Despus  de  copiada  la  imagen,  hay  que arrancar el sistema con el
disquete en la unidad de  floppy.  Al final,  tendrs el pequeo shell
que  hemos  escrito;  ste te  permitir obtener informacin sobre las
rdenes  disponibles  (help),  limpiar  el monitor (clear) y reiniciar
el sistema (exit).

Para  copiar  la  imagen  en  el  disquete  con MBRREST, copiamos este
programa en el  mismo  subdirectorio  donde  se  encuentra  image.img; 
introducimos  un  disquete  en  la  unidad  de  flopppy A y ejecutamos 
la siguiente orden:

	mbrrest image.img

El siguiente guin .BAT compilar todo y copiar la imagen en el 
disquete, siste est ya en la unidad de floppy:

----------------------  MAKE.BAT ---------------------------

del image.img
nasm image.asm -o image.img
if errorlevel 1 goto ERROR
cls
mbrrest image.img
@echo off
goto no_err
:ERROR
@echo ERROR!
pause
:no_err

-------------------------------------------------------------
................

El  programa  slo funcionar en unidades de floppy, porque no incluye
tabla de particin.  Debido a lo  delicada que es la tarea de escribir 
sobre el primer sector de un disco duro,  tan slo haremos comentarios 
al respecto y dejamos al juicio del lector el  realizar la  prctica o 
no de un MBR propio.  Con  la info expuesta aqu se tiene ya una  base 
mnima  para  crear  hasta  un  sencillo  editor de particiones (en el 
Apndice 1  encontrars  un  anlisis  de  un  sector  de  arranque de 
Windows).

Nuestro  programa  consta  de  dos partes,  una pensada para ocupar el 
primer  sector del disco, que contiene el cdigo de arranque.  La otra 
parte ocupar el segundo  sector del disco y ser caragada en  memoria 
por el cdigo del sector de arranque. El cdigo de la segunda parte es 
el pequeo intrprete de rdenes que habamos escrito.  Para probar el 
programa, lo escribiremos en los dos primeros sectores de un disquete, 
y arrancamos el sistema con este disquete en la unidad de floppy,  con 
la opcin de arrancar primero por esta unidad.

El  cdigo del arranque est debidamente comentado.  El  cdigo  de la 
cnsola  ya  lo  revisamos  en el captulo anterior.  En el de cnsola 
hemos hecho un pequeo cambio: hemos reemplazado la orden "quit",  que 
permita salir a DOS, por la orden "help", que despliega una lista  de 
las rdenes disponibles. Como estamos corriendo sin sistema operativo, 
no tiene sentido salir a DOS.

Un  estudio  completo  del  disco incluira el anlisis del sistema de 
archivos del sistema.  Cmo  ahora estamos ocupados en la escritura de 
un  bootstrap,  y  nos  interesa  revisar los registros de sistema del 
procesador,  dejaremos esto de lado pasajeramente y nos concentraremos 
en aprender a cambiar el  modo de ejecucin del procesador.

De todas maneras incluyo algunos apndices  con  cdigo  e  informacin
importante sobre el cdigo y los datos en el  MBR  de  un  disco  duro: 
aqu nos hemos limitado a revisar el sector de arranque de un diaquete.



               * APNDICES *

------------------------------------
Apndice 1: Desensamblaje de un MBR
-------------------------------------
A continuacin,  el  desensamblaje debidamente comentado que hice del 
MBR de de un disco duro.  Para obtenerlo us siguiente programa,  que 
salva a un archivo el primer sector de un disco duro:


; *********************************************************************************
   TITLE BSFSAVE.ASM: Utilidad para recuperar el sector de arranque de un disquete
; *********************************************************************************
;by Evil-E [CodeBreakers]
            
	.MODEL TINY 
	.CODE       
	ORG 100h    
START:
            
	mov     ah,9      	  ; displegar el texto de copyright :-)
	mov     dx,offset msg
	int     21h 
            
	xor     ax,ax             ; reestablecer sistema de disco
	mov     dl,80h
	int     13h 
            
	mov     bp,4              ; leer el sector de arranque bootsector 4 veces ...
read:       
	mov     ax,201h           ; leer el sector
	mov     dx,0          	  ; cabezal 0. Para disco duro: mov dx, 0080h
	mov     cx,1              ; pista 0, sector 1
	mov     bx, offset buffer
	int     13h 
	dec     bp  
	jnz     read
            
	mov     ax,3c00h          ; crear fichero
	xor     cx,cx
	mov     dx,offset file
	int     21h 
	xchg    bx,ax            ; mover filehandle a BX
            
	mov     ah,40h           ; escribir bootsector al archivo boot.bin
	mov     cx,512
	mov     dx,offset buffer
	int     21h 
	jc      error_writing
            
	mov     ah,3eh           ; cerrar archivo
	int     21h 
	int     20h              ; regresar a DOS ...
            
error_writing:
	mov    ah,9              ; displegar un mensaje de error
	mov    dx,offset error
	int    21h  
	int    20h               ; regresar a  DOS ...
            
file   db  'BOOT.BIN',0
msg    db  'SAVE Version 1.0 by Evil-E [CB] (c) 1998',13,10
       db  '----------------------------------------',13,10
       db  'Escribiendo el mbr a boot.bin ...$'
error  db  'ERROR: No se puede escrbir el mbr a boot.bin$',13,10
buffer db  512 dup (0)     ; para salvar el mbr
            
END    START     

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Compilar com: tasm mbrsave
	      tlink /t mbrsave

; ----------------------------------------------------------

El trabajo de desensamblaje lo realic usando:

	BUBBLE CHAMBER:

un buen desensamblador i8086  interactivo,  excelente  para  pequeos 
ficheros en binario.



;********* File: boot.bin *************
;
    code     SEGMENT
             ASSUME CS:code, DS:code
             ORG 00h
  
    start:
; ------------------------------------------------------------------------
; La rutina primero crea una pila (stack) que tiene un tamao de 0:7C00h 
; ------------------------------------------------------------------------
  	XOR	AX, AX		; AX = 0
	MOV	SS, AX          ; SS = 0              
	MOV	SP, 7C00h       ; SP = 007Ch = 
; ---------------------------------------------------------------------
; Inicializar los registros de segmento de datos y el extendido a cero
; ---------------------------------------------------------------------
	STI			; deshabilitar las interrupciones
	PUSH	AX     
	POP	ES    
	PUSH	AX    
	POP	DS    
; ----------------------------------------------------------------------------------
; Se hace que el registro indice de origen (source index: si), apunte al 
; final de la pila + 1Bh (27).
;                     
; El sector se copia a s mismo en la direccin 0:061Bh de la memoria y pasa el control
; a esa direccin, o a la direccin 1Bh de la rutina del sector de arranque, que
; debera ser la siguiente instrucin de la misma rutina
; ----------------------------------------------------------------------------------
	CLD                
	MOV	SI, 7C1Bh        ; Copiar desde 7C1Bh, desde el desplazamiento 27
	MOV	DI, 061Bh        ; Copiar a 061Bh
	PUSH	AX		 ; 0000:
	PUSH	DI		 ; 061B (new_address) en la pila 
	MOV	CX, 01E5h	 ; Copiar 485 bytes = 512 - 27      
	REPZ MOVSB	                              
	RETF                     ; Salta a new_address (0000:061Bh)
; -------------------------------------------------------------------------------------
; Si todo va bien, el fragmento siguiente habr sido copiado en 061Bh y tomar el
; control de la ejecucin.
;
; Inmediatamente se chequea la tabla de particin en 0:07BEh y confirma si se trata de
; un disco duro (valor 080h) que puede arrancar o no. Si no lo es, ejecuta la int 18h
; La tabla de particiones tiene cuatro entradas, as que se hace un bucle de
; cuatro vueltas.                                   
; -------------------------------------------------------------------------------------
new_address:
	MOV     SI, 07BEh       ; 0600+1BEh (446)= direccin de la tab de particiones:
				; 512 - 2 - 16*4 	
        MOV     CL, 4           ; cuatro entradas                                 
        CMP     [SI], CH        ; CH debe valer 0
        JL      J0002D          ; Es menor que cero? (los nmeros negativos tienen 
				; activo el bit ms alto. El nmero 80h = 1000 0000
				; tambin tiene activo el bit ms alto, activando
				; la bandera de signo si este es el caso, provocando
				; un salto.                                  
        JNE     J0003B          ; Tabla no vlida
                                                                  
        ADD     SI, 10h         ; Entrada siguiente: cada entrada tiene 16 (10h) bytes.
J00020: CMP	[SI],CH		; SI apunta a 80h (1000 0000)? 
	JL	J0002D          ; Si el bit 7 del byte a que apunta SI es 1, se activa 
				; SF y se pasa el control a J0002D
	JNZ	J0003B          ; Si no es ni 0 ni 80h, no es una tabla vlida y se sale
	ADD	SI, 10h         ; Siguiente entrada
	LOOP	J00020          ; Revisar las siguientes dos entradas
	INT	18              ; Si se lleg aqu, ninguna particin est activa y se
				; ejecuta int18
; ---------------------------------------------------------------------
; Se ha localizado una particin activa. Se guarda en CX:DX su dir. CHS
; --------------------------------------------------------------------
J0002D: MOV	DX, [SI]        ; En DH 80h y en DL el nmero de cabezal o lado.             
 	MOV	BP, SI		; BP apunta al inicio de la entrada de la
				; particin activa.
; -------------------------------------------------------------------
; Se revisa si otras particiones tienen la bandera = 0. Si no lo
; tienen, entonces la tabla no es vlida               
; -------------------------------------------------------------------
J00031: ADD	SI, 10h		; Apuntar a la siguiente entrada de la tabla
	DEC	CX		; Se verifica si ya no quedan ms entradas
	JZ	J0004D          ; Saltar si no hay otras entradas                         

	CMP	[SI], CH        ; Es correcta esta entrada?
	JZ	J00031          ; Si lo es se revisa la siguiente o seguir si hay error                         
; -------------------------------------------------------------------       
; Rutina que esribe una cadena terminada en cero usando slo el BIOS        
; Si llegamos aqu, es porque la tabla de particin no es vlida.           
; -------------------------------------------------------------------       
J0003B: MOV	SI, offset msg0                                             
J0003E: DEC	SI                                                          
J0003F: LODSB	                                                            
	CMP	AL, 0                                                       
	JZ	J0003E                                                      
	MOV	BX, 0007h                                                   
	MOV	AH, 0Eh                                                     
	INT	10h                                                         
J0004B: JMP	J0003F                                                      
; -------------------------------------------------------------
; Si llegamos aqu, es porque todas las particiones son vlidas
; y una es de arranque
; -------------------------------------------------------------
J0004D: MOV	[BP+25h], AX    ; Mover 0 a un desplazamiento de 37 (25h)
				; bytes por encima de la entrada activa 
				; de la tabla de particiones.
	XCHG	AX, SI		; SI=0 y AX->final de la tabla de particiones.
; ----------------------------------------------------------------	
; Revisar la bandera de sistema operativo. Nos dice cul es el SO
; ----------------------------------------------------------------
 	MOV	AL, [BP+04h]	; Mover a AL el tipo de particin
	MOV	AH, 06h
	CMP	AL, 0Eh		; 0Eh = FAT16 con extensiones LBA1 13h?
	JZ	J0006B                                                      
                                                                            
	MOV	AH, 0Bh
	CMP	AL, 0Ch		; 0Ch = FAT32 con extensiones?
	JZ	J00065                                                      
                                                                            
	CMP	AL, AH		; 06 o 0Bh = FAT16 o FAT32?
	JNZ	J0008F                                                     
	INC	AX
; ----------------------------------------------------------------------
; Si es una particin tipo 0Eh o 0Bh, se pone 6 en [BP+25h]
; ----------------------------------------------------------------------
J00065: MOV	BYTE PTR [BP+25h], 06h
	JNZ	J0008F			; si no es ninguno de estos valores
					; se salta el siguiente cdigo
; ---------------------------------------------------------------------------
; Chequeo de la instalacin. El servicio 41h de la int13 chequea si se trata
; de una particin activa, con 55AAh (la signatura) en el desplazamiento 510
; del MBR
; ---------------------------------------------------------------------------	      
J0006B: MOV	BX, 55AAh
	PUSH	AX
	MOV	AH, 41h
	INT	13h
; --------------------------------------------	
; Si CF es 1 hay error                                                                            
; --------------------------------------------	
	POP	AX			; SP-2 = 7C00h-2
	JB	J0008C          	; Salta si hay error                                
        ; Est instalado el disco?                   
	CMP	BX, AA55h
	JNZ	J0008C          	; Salta si no se ha instalado disco 
        ; El subconjunto API soporta bitmap?
	TEST	CL, 01h
	JZ	J0008C
; -----------------------------------------------------------	
; Lee el sector de arranque del disco y lo escribe en 7C00h 
; -----------------------------------------------------------	
 	MOV	AH, AL
	MOV	[BP+24h], DL		; indicador de unidad
	MOV	WORD PTR [06A1h], 1EEBh ; en el desplazamiento A1h se escribe
					; un salto a A3h+1Eh = 06C1h = J000C1
J0008C: MOV	[BP+04h], AH

J0008F: MOV	DI, 000Ah
J00092: MOV	AX, 0201h		; leer un sector
	MOV	BX, SP			; BX apunta al tope de la pila: ah se escribir el cdigo
					; siguiente.
	XOR	CX, CX			; CX = 0
	CMP	DI, 05h			; DI = 5?
	JG	J000A1			; 
	MOV	CX, [BP+25h]		; CX = 0 o 6 (se haba puesto 0 o 6 en BP + 25h)
J000A1: ADD	CX, [BP+02h]		; Cilindro/sector de inicio de la particin
	INT	13h
	                         
J000A6: JB	J000D1                  ; Error de lectura
	MOV	SI, offset buff         ; 0764h
	CMP	BootSig, 0AA55h         ; [7DFE]
	JZ	J0010D                  ; Si la signatura est en su lugar, saltar
                                                                    
	SUB	DI,05h                                             
	JG	J00092                                              
                                    
J000B8: TEST	SI,SI               
	JNZ	J0003F           
                                                                        
	MOV	SI, offset str1         ; 072Ch: Error de carga                                             
	JMP	J0004B                                
                                
J000C1: CBW
        XCHG    CX,AX
        PUSH    DX
        CWD
        ADD     AX,[BP+08]
        ADC     DX,[BP+0A]
        CALL    06E0
        POP     DX
        JMP     06A6
                                                       
J000D1: DEC	DI              
	JZ	J000B8                                  
; ----------------------                               
; Restablecer la unidad         
; ----------------------                              
	XOR	AX,AX				; Servicio 0   
	INT	13		       		; de la int13
	JMP	J00092                                                 


	ADD	[BX+SI], AL
       	ADC	BYTE PTR [SI], 34h                      
	ADC	DX, [BP+33h]
	NOT	BYTE PTR [BP+56h]

; -----------------------------------------------------------------------
; Realizar una lectura extendida del sector. SI -> direccin del paquete 
; en el disco
; -----------------------------------------------------------------------
J006E0: PUSH    SI
        XOR     SI,SI
        PUSH    SI
        PUSH    SI
	PUSH	DX
	PUSH	AX                               
	PUSH	ES                                        
	PUSH	BX                               
	PUSH	CX                               
	MOV	SI ,0010h                        
	PUSH	SI                               

	MOV	SI, SP                                  
	PUSH	AX                                
	PUSH	DX                               
	MOV	AX, 4200h			; Servicio 42h                        
	MOV	DL, [BP+24h]                    ; 
    	INT	13                              ; De la int13 
	POP	DX                                                     
  	POP	AX                                    
	LEA	SP, [SI+10h]    ; Dir de la bandera de 64 bits del buffer
	JB	J0010B          ; Saltar si hubo error                                         

J00101: INC	AX                                    
	JNZ	J00105                           
	INC	DX                               
J00105: ADD	BH,02h                                    
	LOOP	J00101                           

	CLC	                                 
J0010B: POP	SI                               
	RETN	                ; salto cercano

J0010D: JMP	SHORT J00183                     

msg0	DB	"Tabla de partici", F3h, "n no v", 0E1h, "lida", 0
msg1	DB	"Se ha producido un error al cargar el sistema operativo.", 0			;00159
buff	DB	 30 DUP (00h)			;00164                  

; ----------------------------------------------------------------------------------                           
; Pasar el control a DS:DI = 0000:7C00, donde debe encontrarse el cdigo que sigue
; a ste. 
; ---------------------------------------------------------------------------------- 
J00183: MOV	DI, SP                                 
	PUSH	DS                              
	PUSH	DI                                     
	MOV	SI, BP                           
	RETF			; saltar al sistema operativo
				; El cdigo del sector de arranque est en 
				; 0000:7C00 y contina el proceso de arranque 

	DB	"artition"			;0018A
	DB	0Ah				;00192
	DB	0Dh    				;00193

	DB	 28 DUP (00h)			;00194
	DB	"PQ"				;001B0
	DB	02h				;001B2 
	DB	03h				;001B3
	DB	04h				;001B4
	DB	05h				;001B5
	DB	00h				;001B6
       	DB	03h				;001B7                  
	DB	"I"				;001B8                 
	DB	D8h				;001B9
	DB	A9h				;001BA
	DB	A4h				;001BB  
	DB	2 DUP (00h)			;001BC

; Tabla de particiones                                
        ; --------------------------------------------	
        ; Primera entrada
        ; --------------------------------------------	
boot	DB	00h	 			;001BE 
iniHe   DB	01h			        ;001BF
iniSs 	DB	00h				;001C0
iniCi  	DB	00h				;001C1
        ; --------------------------------------------	
OSflg	DB	0Bh				;001C2 ; FAT de 32-bit (Particin de hasta 2048GB)
endHe  	DB	3Fh				;001C3
endSe  	DB	BFh				;001C4
endCi  	DB	3Eh                             ;001C5                  
        ; --------------------------------------------	
     	DD      3F000000h       		;001C6
        ; -------------------------------------------- 	
lenght	DD	01602300h			;001CA  
        ; --------------------------------------------	

        ; --------------------------------------------	
        ; Segunda entrada                                                        
        ; -------------------------------------------- 	
     	DB	80h	 			;001CE <- Esta es la particin activa
	DB	00h	    			;001CF 
	DB	81h				;001D0 
	DB	3Fh				;001D1 
        ; -------------------------------------------- 	
        DB	81h				;001D2 <- MINIX o Linux
	DB	0Fh				;001D3  
	DB	BFh				;001D4  
	DB	6Ch                                     
        ; -------------------------------------------- 	                
	DB      40h, 60h, 23h                   ;001D5          
 	DB	00h   				;001D9  
        ; --------------------------------------------	
	DB	B0h				;001DA  
	DB	C8h				;001DB  
	DB	02h				;001DC  
 	DB	00h   				;001DD  
        ; --------------------------------------------	

        ; --------------------------------------------	
        ; Otras dos entradas                            
        ; --------------------------------------------	
	DB	32 DUP (00h)			;001DE  
        ; --------------------------------------------	

        ; --------------------------------------------	
        ; Signatura del sector de arranque
        ; --------------------------------------------	
BootSig	DW      55AAh                           ;001FE
        ; --------------------------------------------	

    code     ENDS
             END  start                                  

        ; --------------------------------------------	



Resumamos qu hace esta rutina.

1. Reserva un espacio en la memoria (pila) con un tamao 07Ch=124 bytes

  	XOR	AX, AX		; AX = 0
	MOV	SS, AX          ; SS = 0              
	MOV	SP, 7C00h       ; SP = 007Ch = 124 bytes

2. Inicializa los registros de segmento de datos y el extendido a cero.

   Hace que el registro indice de origen (source index: si),  apunte al 
   final de la pila + 1Bh (27).

	CLD                
	MOV	SI, 7C1Bh        ; Copiar desde 7C1Bh, desde el
				 ; desplazamiento 27

   El  sector se copia a s mismo en la direccin  0:061Bh-01E5h de la
   memoria y pasa el control a esa direccin,  o a la direccin 1Bh de 
   la rutina del sector de arranque, que debera ser la instrucin que 
   sigue la ltima de esta rutina

	CLD			 ; Copiar desde el final	
	MOV	DI, 061Bh        ; Copiar desde 0:061Bh
	PUSH	AX		 ; 0000:
	PUSH	DI		 ; 061Bh en la pila 
	MOV	CX, 01E5h	 ; Copiar 485 bytes = 512 - 27      
	REPZ    MOVSB	                              
	RETF                     ; Salta a 0000:061Bh

   El control se pasa a 0000:061Bh de una manera peculiar: se emplea la
   instruccin RETF,  que pasa el control a la direccin indicada en el
   tope de la pila, y que est indicado por el registro puntero de pila
   SP. A diferencia de RET, la instruccin RETF usa direccionamiento de
   memoria, base:desplazamiento. En este caso sera 0000:061Bh,  puesto 
   primero con "PUSH AX" (AX=0) y "MOV DI, 061Bh - PUSH DI".  Antes  de 
   pasar el control a esta direccin, se movi el resto del MBR a  esta 
   direccin. 

   Luego revisa la tabla de particiones en busca de alguna  activa.  El
   primer byte en la tabla debe contener 0, vlida pero inactiva, u 80h, 
   vlida y activa:
  

new_address:
	MOV     SI, 07BEh       ; 0600+1BEh (446)= direccin de la tab de particiones:
				; 512 - 2 - 16*4 	
        MOV     CL, 4           ; cuatro entradas                                 
        CMP     [SI], CH        ; CH debe valer 0
        JL      J0002D          ; Es menor que cero? (los nmeros negativos tienen 
				; activo el bit ms alto. El nmero 80h = 1000 0000
				; tambin tiene activo el bit ms alto, activando
				; la bandera de signo si este es el caso, provocando
				; un salto.                                  
        JNE     J0003B          ; Tabla no vlida
                                                                  
        ADD     SI, 10h         ; Entrada siguiente: cada entrada tiene 16 (10h) bytes.
J00020: CMP	[SI],CH		; SI apunta a 80h (1000 0000)? 
	JL	J0002D          ; Si el bit 7 del byte a que apunta SI es 1, se activa 
				; SF y se pasa el control a J0002D
	JNZ	J0003B          ; Si no es ni 0 ni 80h, no es una tabla vlida y se sale
	ADD	SI, 10h         ; Siguiente entrada
	LOOP	J00020          ; Revisar las siguientes dos entradas

   Si no se encontr ninguna particin activa se ejecuta la int18:

	INT	18h             ; Si se lleg aqu, ninguna particin est activa y se
				; ejecuta int18

   Al final se copia el cdigo relevante en la particin activa en 7C00h
   y se le pasa el control:

; -----------------------------------------------------------	
; Lee el sector de arranque del disco y lo escribe en 7C00h 
; -----------------------------------------------------------	
 	MOV	AH, AL
	MOV	[BP+24h], DL		; indicador de unidad
	MOV	WORD PTR [06A1h], 1EEBh ; en el desplazamiento A1h se escribe
					; un salto a A3h+1Eh = 06C1h = J000C1
J0008C: MOV	[BP+04h], AH

J0008F: MOV	DI, 000Ah
J00092: MOV	AX, 0201h		; leer un sector
	MOV	BX, SP			; BX apunta al tope de la pila: ah 
					; se escribir el cdigo siguiente.
	XOR	CX, CX			; CX = 0
	CMP	DI, 05h			; DI = 5?
	JG	J000A1			; 
	MOV	CX, [BP+25h]		; CX = 0 o 6 (se haba puesto 0 o 6 en BP + 25h)
J000A1: ADD	CX, [BP+02h]		; Cilindro/sector de inicio de la particin
	INT	13h
	                         
J000A6: JB	J000D1                  ; Error de lectura
	MOV	SI, offset buff         ; 0764h
	CMP	BootSig, 0AA55h         ; [7DFE]
	JZ	J0010D                  ; Si la signatura est en su lugar, saltar
					; particin activa.

   Imagino  que  con  esta  informacin  ya se estar en condiciones de 
   escribir un  programa para leer y escribir la tabla de particin del 
   disco  duro.  Eso  queda  de  ejercicio  para  el  lector.  Slo  le 
   recomiendo  precaucin  y  que  siempre  tenga  un  respaldo del MBR 
   original de su disco por si acaso.



---------------------------------------
Apndice 2: Anidamiento de la particin
---------------------------------------
Es posible anidar una particin en otra. Vemoslo con un ejemplo:

     M = MBR (y cualquiera de los sectores en la misma pista [track])

     E = Extended  partition record:  (y cualquiera de los sectores en 
         la misma pista [track])

   pri = una particin primaria (el  primer  sector  es  un sector  de 
         "arranque")

   sec = una  particin  secundaria  (el  primer  sector es un  sector 
         "arranque")


  |<---------------- Todo el disco -------------->|
  |                                               |
  |M<pri>                                         |
  |                                               |
  |     E<sec><---- resto de la 1ra part ext ---->|
  |                                               |
  |           E<sec><- resto de la 2da part ext ->|
  |                                               |


La  primera  particin  extendida es descrita en el MBR y ocupa todo el 
resto del disco que sigue a la particin primaria. La segunda particin 
extendida  es descrita en el *record* de la primera particin extendida 
y  ocupa  todo  el  resto  del  disco  que sigue a la primera particin 
secundaria.


-------------------------------------------
Apndice 3: Enlace de la tabla de particin
-------------------------------------------
Las tablas o *records* de la particin pueden formar listas  enlazadas.  
Esto significa que el MBR tiene una entrada que  describe (apunta a) la 
primera particin extendida, la primera tabla de la particin extendida 
tiene  una entrada  que describe (apunta a)  la  segunda  tabla  de  la 
particin extendida, y as. En teora no hay lmite para el tamao  del
enlace. Cuando se pide a FDISK que muestre las "unidades lgicas"  DOS, 
lee las listas enlazadas en busca de todas las particiones  de tipo DOS 
FAT.  Hay  que recordar  que en una tabla de particin extendida,  slo 
pueden usarse dos de cuatro entradas.

Una cosa ms.  Dentro de una particin, la disposicin de los datos del 
sistema de  archivos vara enormemente.  Sin embargo,  se espera que el 
primer sector de una particin sea el sector de "arranque".  Un sistema 
de archivos DOS FAT  tiene:  un sector de arranque,  los sectores de la 
primera FAT, los sectores de la segunda FAT, los sectores del directorio 
raiz y finalmente el rea de archivos de datos.


---------------------------------------------
Apndice 4: Indicadores de tipo de particin
---------------------------------------------

 00h	vaca
 01h	DOS FAT de 12-bits
 02h	XENIX (sistema de archivo root)
 03h	XENIX (sistema de archivo /usr (obsoleto) )
 04h	DOS FAT de 16-bits (hasta 32M)
 05h	DOS 3.3+ (particin extendida)
 06h	DOS 3.31+ Sistemas de archivos grandes (FAT de 16-bits, ms de 32M)
 07h	QNX
 07h	OS/2 HPFS
 07h	Windows NT NTFS
 07h	Unix Avanzado
 08h	AIX: particin activa, SplitDrive
 09h	AIX: particin de datos
 09h	Sistema de archivos coherente
 0Ah	OS/2 Manager de arranque
 0Ah	OPUS
 0Ah	Particin de intercambio (swap) coherente
 10h	OPUS
 11h	OS/2 Manager de arranque escondido: particin FAT de 12-bits
 12h	Compaq: particin de diagnsticos
 14h	(resulted from using Novell DOS 7.0 FDISK to delete Linux Native part)
 14h	OS/2 Manager de arranque escondido: particin FAT de 16-bits sub-32M
 16h	OS/2 Manager de arranque escondido: particin FAT de 16-bits sobre-32M
 17h	OS/2 Manager de arranque escondido: particin HPFS
 18h	AST special Windows swap file
 24h	NEC MS-DOS 3.x
 3Ch	PowerQuest PartitionMagic: particin de recuperacin
 40h	VENIX 80286
 42h	SFS (Secure File System) por Peter Gutmann
 50h	Disk Manager, particin de slo lectura
 51h	Disk Manager, particin de lectura/escritura
 51h	Novell???
 52h	CP/M
 52h	Microport System V/386
 56h	GoldenBow VFeature
 61h	SpeedStor
 63h	Unix SysV/386, 386/ix
 63h	Mach, MtXinu BSD 4.3 sobre Mach
 63h	GNU HURD
 64h	Novell NetWare
 65h	Novell NetWare (3.11)
 70h	DiskSecure Multi-Boot
 75h	PC/IX
 80h	Minix v1.1 - 1.4a
 81h	Minix v1.4b+
 81h	Linux
 81h	Mitac: Manager Avanzado de Disco (Advanced Disk Manager)
 82h	Linux: particin de intercambio (Swap)
 83h	Linux: sistema de archivos nativo [native file system] (ext2fs/xiafs)
 84h	OS/2- tipo reenumerado: particin 04h (relativa a la unidad escondida DOS C:)
 93h	Amoeba: sistema de archivos
 94h	Amoeba: tabla de bloques malos [bad block table]
 A5h	FreeBSD
 B7h	BSDI: sistema de archivos (secundariamente de intercambio --swap)
 B8h	BSDI: particin de intercambio (Swap) (secundariamente de sistema de archivos)
 C1h	DR-DOS 6.0 LOGIN.EXE-particin FAT de 12-bits asegurada
 C4h	DR-DOS 6.0 LOGIN.EXE-particin FAT de 16-bits asegurada
 C6h	DR-DOS 6.0 LOGIN.EXE-particin enorme asegurada [secured Huge partition]
 C7h	Cyrnix Boot
 DBh	CP/M, CP/M Concurrente, DOS Concurrente
 DBh	CTOS (Convergent Technologies OS)
 E1h	SpeedStor particin FAT de 12-bits
 E4h	SpeedStor particin FAT extendida de 16-bits
 F2h	DOS 3.3+ secundaria
 F4h	SpeedStor
 FEh	LANstep
 FFh	Xenix tabla de bloques malos [bad block table]

------------------------------------------------ TO BE CONTINUED ----------->

emailme: numit_or@cantv.net
webZ: http://mipagina.cantv.net/numetorl869/
      http://oberon.spaceports.com/~tutorial/aks/


