UNIVERSIDAD CENTRAL DEL ECUADOR FACULTAD DE INGENIERÍA, CIENCIAS FÍSICAS Y MATEMÁTICA CARRERA INGENIERÍA INFORMÁTICA ESTUDIO, DESARROLLO E IMPLEMENTACIÓN DE UN GESTOR DE ARRANQUE PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL. TRABAJO DE GRADUACIÓN PREVIA LA OBTENCIÓN DEL TÍTULO DE INGENIERO INFORMÁTICO. AUTOR: Figueroa Cañar Víctor Bolívar TUTOR: Ing. Jorge Arturo Morales Cardoso QUITO - ECUADOR 2015 DEDICATORIA Dedico el presente trabajo de tesis a Dios por cuidarme y guiarme en cada momento de mi vida, a mis padres Luis Antonio y María Beatriz por su permanente apoyo, por plasmar en mi educación, valores y disciplina ante todas las cosas que he desarrollado en mi vida, a mis hermanos Luis, Andrés y Nélida por su ayuda y consejos, me han inspirado a lo largo de mi vida personal y profesional. Dedico a mi Familia y amigos/as que han estado en los momentos que los he necesitado con su apoyo, entusiasmo y alegría. A todos ustedes gracias por su incondicional apoyo y entusiasmo que me han inspirado para poder culminar el presente tema de tesis. Víctor Figueroa II AGRADECIMIENTO Agradezco la colaboración, enseñanza y ayuda de los Ing. Jorge Morales como tutor de tesis, Ing. Mauro Rosas como revisor de tesis, por su apoyo durante el desarrollo del tema de tesis, a los docentes de la carrera de Ingeniería Informática por impartir sus conocimientos los cuales me ayudaron a culminar el tema. Agradezco a toda mi familia por su apoyo y cariño inagotable, gracias por estar siempre juntos. Agradezco a mis amigos/as de la Universidad con los cuales compartí inolvidables momentos, gracias por su apoyo. Víctor Figueroa III AUTORIZACIÓN DE LA AUTORÍA INTELECTUAL Yo, Figueroa Cañar Víctor Bolívar en calidad de autor del trabajo de investigación o tesis IMPLEMENTACIÓN realizada DE UN sobre GESTOR ESTUDIO, DE DESARROLLO ARRANQUE E PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL, por la presente autorizo a la UNIVERSIDAD CENTRAL DEL ECUADOR, hacer uso de todos los contenidos que me pertenecen o de parte de los que contiene esta obra, con fines académicos o de investigación. Los derechos que como autor me corresponden, con excepción de la presente autorización, seguirán vigentes a mi favor, de conformidad con los establecidos en los artículos 5, 6, 8, 19 y demás pertinentes de la ley de Propiedad Intelectual y su Reglamento. Quito, Día 21 Mes Abril 2015 ---------------------------FIRMA Figueroa Cañar Víctor Bolívar CC. 1716500317 IV CERTIFICACIÓN En calidad de tutor del proyecto de investigación: ESTUDIO, DESARROLLO E IMPLEMENTACIÓN DE UN GESTOR DE ARRANQUE PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL, presentado y desarrollado por el señor: Figueroa Cañar Víctor Bolívar , previo a la obtención del Título de Ingeniero Informático considero que el proyecto reúne los requisitos necesarios. En la ciudad de Quito a los 21 días del mes de Abril del 2015 Atentamente -------------------------------Ing. Jorge Arturo Morales Cardoso Tutor de Tesis V INFORME SOBRE CULMINACIÓN Y APROBACIÓN DE TESIS Quito, DM 21 de Abril del 2015 Señor Ingeniero Boris Herrera DIRECTOR DE LA CARRERA DE INGENIERÍA INFORMÁTICA Presente.- Señor Director: Yo, Jorge Arturo Morales Cardoso, Docente de la Carrera de Ingeniería Informática, de la Facultad de Ingeniería Ciencias Físicas y Matemáticas de la Universidad Central del Ecuador y en calidad de tutor. Certifico Luego de las revisiones técnicas realizadas por mi persona al proyecto de investigación “ESTUDIO, DESARROLLO E IMPLEMENTACIÓN DE UN GESTOR DE ARRANQUE PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL” llevando a cabo por parte del egresado de la Carrera de Ingeniería Informática, señor Víctor Bolívar Figueroa Cañar, con CC. 1716500317 ha concluido de manera exitosa, consecuentemente el indicado egresado podrá continuar con los trámites de graduación correspondientes de acuerdo a lo que estipula las normativas y direcciones legales. Por la atención que digne al presente, reitero mi agradecimiento. Atentamente Ing. Jorge Arturo Morales Cardoso CATEDRÁTICO DE LA CARRERA DE INGENIERÍA INFORMÁTICA Tutor VI RESULTADO DEL TRABAJO DE GRADUACION VII CONTENIDO DEDICATORIA ................................................................................................... II AGRADECIMIENTO .......................................................................................... III AUTORIZACIÓN DE LA AUTORÍA INTELECTUAL ......................................... IV CERTIFICACIÓN ................................................................................................ V INFORME SOBRE CULMINACIÓN Y APROBACIÓN DE TESIS .................... VI RESULTADO DEL TRABAJO DE GRADUACION .......................................... VII LISTA DE FIGURAS ........................................................................................ XII LISTA DE TABLAS ......................................................................................... XIV RESUMEN ........................................................................................................ XV ABSTRACT ..................................................................................................... XVI CERTIFICADO DE TRADUCCIÓN ................................................................ XVII TÍTULO DEL TRADUCTOR .......................................................................... XVIII INTRODUCCIÓN ................................................................................................ 1 CAPITULO 1....................................................................................................... 2 1. PRESENTACION DEL PROBLEMA ....................................................... 2 1.1 Planteamiento del Problema............................................................... 2 1.2 Formulación del Problema .................................................................. 4 1.3 Justificación ......................................................................................... 4 1.4 Objetivos de la Investigación ............................................................... 5 1.4.1 Objetivo General ............................................................................. 5 1.4.2 Objetivos Específicos ...................................................................... 5 1.6 Alcance................................................................................................ 6 1.7 Limitaciones ........................................................................................ 7 1.8 Contribuciones .................................................................................... 8 1.9 Herramientas ....................................................................................... 9 CAPITULO 2..................................................................................................... 10 2. MARCO METODOLÓGICO.................................................................... 10 2.1 Diseño de la Investigación................................................................. 10 2.2 Antecedentes .................................................................................... 11 2.3 Fundamentación Teórica ................................................................... 12 2.3.1 Evolución De Los Sistemas Operativos y Computadores ............. 12 2.3.1.1 Primera Generación (1946-1958) ............................................ 13 2.3.1.2 Segunda Generación (1955 a 1965) ........................................ 13 VIII 2.3.1.3 Tercera Generación (1965 a 1980) .......................................... 14 2.3.1.4 Cuarta Generación (1965 a 1980) ........................................... 14 2.3.1.5 Historia Hechos Relevantes ..................................................... 15 2.3.2 Microprocesador ........................................................................... 16 2.3.2.1 Concepto ................................................................................. 16 2.3.2.2 Evolución del microprocesador ................................................ 16 2.3.2.3 Arquitectura ............................................................................. 18 2.3.2.4 Registros .................................................................................. 19 2.3.2.5 Unidad aritmética lógica ........................................................... 22 2.3.3 Memoria ......................................................................................... 24 2.3.3.1 Tipos de Memoria .................................................................... 24 2.3.3.1.1 Memoria RAM .................................................................... 24 2.3.3.1.1 Memoria ROM ................................................................... 25 2.3.3.2 Memoria Principal .................................................................... 26 2.3.3.3 Arquitectura de la Memoria Principal ....................................... 26 2.3.4 Manejo de Memoria ....................................................................... 30 2.3.4.1 Segmentación .......................................................................... 30 2.3.4.2 Direccionamiento .................................................................... 31 2.3.4.3 Modos de Direccionamiento .................................................... 32 2.3.5 Disco Duro ................................................................................. 36 2.3.5.1 Estructura Física De Un Disco Duro ........................................ 36 2.3.5.2 Estructura Física: Cabezas, Cilindros Y Sectores.................... 39 2.3.5.3 Direccionamiento De Sectores En Discos Duros .................... 40 2.3.5.3.1 Direccionamiento CHS ...................................................... 40 2.3.5.3.2 Direccionamiento CHS Extendida...................................... 41 2.3.5.3.3 Direccionamiento LBA ....................................................... 42 2.3.6 Sistema De Numeración Computacional Y Unidades De Información ............................................................................................. 44 2.3.6.1 Sistema Binario ........................................................................ 44 2.3.6.2 Sistema Octal........................................................................... 44 2.3.6.3 Sistema Decimal ...................................................................... 44 2.3.6.4 Sistema Hexadecimal .............................................................. 45 2.3.6.5 Unidades De Información ........................................................ 45 2.3.7 BIOS .......................................................................................... 46 2.3.7.1 El área de parámetros de la BIOS ........................................... 47 2.3.7.2 Vectores de Interrupción .......................................................... 49 2.3.7.3 Servicios De La BIOS .............................................................. 50 2.3.8 Lenguaje Ensamblador .............................................................. 51 2.3.9 Lenguaje C................................................................................. 52 2.3.10 Herramientas de programación .............................................. 53 2.3.10.1 Editores .................................................................................. 53 IX 2.4 2.5 2.6 2.7 2.3.10.2 Ensambladores ...................................................................... 55 2.3.10.3 Enlazadores ........................................................................... 56 2.3.10.4 GCC ....................................................................................... 57 Investigación Experimental ................................................................ 58 Plan de Recolección de Información ................................................... 58 Plan de Procesamiento de Información ............................................... 59 Modelo de Desarrollo .......................................................................... 59 CAPITULO 3..................................................................................................... 62 3 DISEÑO DE LA SOLUCIÓN.................................................................... 62 3.1 Antecedentes .................................................................................... 62 3.2 Gestor de Arranque ........................................................................... 62 3.2.1 Codificación y Funcionamientos de los Gestores de Arranque ... 63 3.3 MBR .................................................................................................. 64 3.4. NTLDR ............................................................................................ 65 3.4.1 Estudio NTLDR ........................................................................... 65 3.4.1 .1 Sección de Código............................................................... 66 3.4.1 .2. Sección de Mensaje de Errores ............................................. 67 3.4.1 .3 Sección definida por Windows ............................................ 67 3.4.1 .4 Sección Tabla de Particiones .............................................. 68 3.4.1 .5. Sección de Firma ................................................................ 72 3.4.2. Des ensamblaje de la Sección de Código ................................. 73 3.4.2. 1. Primera Parte Del Código ................................................... 73 3.4.2. 2. Segunda Parte Del Código ................................................. 74 3.4.2. 3. Tercera Parte Del Código ................................................... 76 3.4.2. 4. Cuarta Parte Del Código .................................................... 77 3.4.2. 5. Quinta Parte Del Código. ................................................... 78 3.4.2. 6. Sexta Parte Del Código ..................................................... 84 3.4.3. Alcance estudio NTLDR............................................................ 86 3.5 GRUB LEGACY .............................................................................. 86 3.5.1 Introducción GRUB .................................................................... 86 3.5.2 Historia de GRUB ...................................................................... 87 3.5.3 Características de GRUB ............................................................ 87 3.5.4 Creación de un disquete de arranque GRUB ............................. 92 3.5.5 Realizar un CD-ROM Booteable con GRUB .............................. 93 3.5.5 Construcción y Compilación de GRUB .................................... 101 3.5.6 Estudio del Código de GRUB .................................................. 108 3.5.6 .1 Estudio Del Código De La Primera Etapa.......................... 109 3.5.7 .1 Primera parte del Código .................................................. 121 3.5.7 .2 Segunda parte del Código ................................................ 122 3.5.7.3 Tercera parte del Código ................................................... 123 X 3.5.7.4 Cuarta parte del Código..................................................... 124 3.5.7.5 Quinta parte del Código ..................................................... 128 3.6 Modificación del Gestor de Arranque GRUB .................................. 144 3.6.1 Modificación Del Archivo stage1.S............................................ 145 3.6.2 Modificación del Archivo stage1.h............................................ 159 3.6.3 Modificación del Archivo char_io.c ........................................... 162 3.6.4 Presentación Del funcionamiento De Grub Legacy Modificado. ........................................................................................................... 199 3.6.4.1 Pantalla Inicial Grub Legacy Modificado ............................... 200 3.6.4.2 Grub Legacy Modificado Chainloader ................................... 200 3.7 Desarrollo de MUCE (MBR de la Universidad Central del Ecuador) 201 3.7.1 Código de MUCE ...................................................................... 201 CAPITULO 4................................................................................................... 206 4.1 PRUEBAS ................................................................................................ 206 4.1.1 Presentación Funcionamiento MUCE............................................. 206 4.1.1.1 Pantalla Inicial MUCE................................................................ 206 4.1.1.2 Pantalla Inicio Windows Xp ................................................ 207 4.2 CONCLUSIONES ....................................................................................... 207 4.3 RECOMENDACIONES ................................................................................. 208 BIBLIOGRAFIA .............................................................................................. 209 XI LISTA DE FIGURAS Figura 1. Abstracción de Interfaz Aplicaciones y S.O. ...................................... 12 Figura 2. Procesamiento por Lotes ................................................................... 13 Figura 3. Arquitectura de Microprocesador o CPU 8086. ................................. 18 Figura 4. Esquema de Bloques de una ALU Típica. ......................................... 23 Figura 5. Memoria Típica. ................................................................................. 24 Figura 6. Arquitectura de la Memoria Principal. ................................................ 26 Figura 7. Segmentación de Memoria ................................................................ 31 Figura 8. Direccionamiento Directo. .................................................................. 33 Figura 9. Direccionamiento indirecto mediante registro. ................................... 34 Figura 10. Direccionamiento por Registro Base ............................................... 34 Figura 11. Direccionamiento indexado.............................................................. 35 Figura 12. Disco Duro. ...................................................................................... 36 Figura 13. Estructura Física De Un Disco Duro. ............................................... 36 Figura 14. Estructura física de un disco duro. ................................................... 39 Figura 15. Editor Assembler Editor. .................................................................. 54 Figura 16. Editor Nasm-IDE. ............................................................................. 54 Figura 17. Etapas de gcc. ................................................................................. 57 Figura 18. Flujo General de Inicio de la Pc. ...................................................... 62 Figura 19. Flujo de Selección y Carga de Código de Arranque. ....................... 63 Figura 20. Sector Cero Disco Duro con Windows XP. ...................................... 65 Figura 21. Sección de código de NTLDR. ......................................................... 66 Figura 22. Sección de Mensaje de Errores. ...................................................... 67 Figura 23. Sección definida por Windows parte 1. ............................................ 67 Figura 24. Sección definida por Windows parte 2. ............................................ 68 Figura 25. NTLDR Sección Tabla de Particiones.............................................. 68 Figura 26. NTLDR Tipo de Particiones. ............................................................ 71 Figura 27. Tabla de Particiones Hexadecimal................................................... 71 Figura 28. NTLDR Firma. .................................................................................. 72 Figura 29. Terminal en Modo Grafico. ............................................................ 102 Figura 30. Comando cd. ................................................................................. 102 Figura 31. Comando zcat. ............................................................................... 103 Figura 32. Ejecución del comando zcat. ......................................................... 103 Figura 33. Creación del directorio grub-097. ................................................... 104 Figura 34. Contenido del directorio grub-097. ................................................. 104 Figura 35. Archivos del directorio stage1. ....................................................... 105 Figura 36. Ingreso Subdirectorio Grub-0.97. ................................................... 105 Figura 37. Ejecución de ./configure CC=gcc34 ............................................... 106 Figura 38. Listado de ./configure CC=gcc34. .................................................. 106 XII Figura 39. Ejecución del archivo install. .......................................................... 107 Figura 40. Salida del comando make install. .................................................. 107 Figura 41. Código hexadecimal de GRUB Primera Etapa. ............................. 109 Figura 42. Configuración des ensamblaje. ...................................................... 110 Figura 43. Ingreso a Directorio stage1. ........................................................... 114 Figura 44. Creación de archivo total fuente stage1. ........................................ 115 Figura 45. Código hexadecimal diferenciado de GRUB Primera Etapa. ......... 120 Figura 46. Código Hexadecimal GRUB parte 1 .............................................. 121 Figura 47. Código Hexadecimal GRUB parte 2. ............................................. 122 Figura 48. Código Hexadecimal GRUB parte 2. ............................................. 123 Figura 49. Inico Grub Legacy Modificado. ...................................................... 200 Figura 50. Inico Grub Legacy Chainloader. .................................................... 200 Figura 51. Inicio MUCE. .................................................................................. 206 Figura 52. MUCE Iniciando XP ....................................................................... 207 XIII LISTA DE TABLAS Tabla 1. Evolución De Los Microprocesadores. ................................................ 17 Tabla 2. Registros del Microprocesador 80386................................................. 19 Tabla 3. Uso común de los registros de propósito general. .............................. 19 Tabla 4. Uso común de los registros de segmento. .......................................... 19 Tabla 5. Registros apuntadores del microprocesador....................................... 20 Tabla 6. Banderas del microprocesador. .......................................................... 21 Tabla 7. Tipos de Memoria. .............................................................................. 25 Tabla 8. Direccionamiento CHS. ....................................................................... 40 Tabla 9. Especificación ATA. ............................................................................ 41 Tabla 10. Unidades de Información Microprocesador. ...................................... 46 Tabla 11. Área De Parámetros De La BIOS. .................................................... 48 Tabla 12. Tipos de Datos de Programación C. ................................................ 52 Tabla 13. Etapas del Gestor de Arranque. ........................................................ 63 Tabla 14. Almacenamiento del Master Boot Record de NTLDR. ...................... 66 Tabla 15. Estructura de la tabla de particiones. ................................................ 69 Tabla 16. NTLDR código fuente documentado parte 1. .................................... 74 Tabla 17. NTLDR código fuente documentado parte 2. .................................... 75 Tabla 18. NTLDR código fuente documentado parte 3. .................................... 76 Tabla 19. NTLDR código fuente documentado parte 4. .................................... 77 Tabla 20. NTLDR código fuente documentado parte 5. .................................... 83 Tabla 21. NTLDR código fuente documentado parte 6. .................................... 85 Tabla 22. Archivo de Configuración de Menú de GRUB. .................................. 99 Tabla 23. Codigo NTLDR. ............................................................................... 114 Tabla 24. Codigo GRUB parte 1. .................................................................... 121 Tabla 25. Código GRUB desensamblado parte 1. .......................................... 122 Tabla 26. Código GRUB parte 2. .................................................................... 123 Tabla 27. Código GRUB Parte 3. .................................................................... 124 Tabla 28. Código GRUB parte 4. .................................................................... 128 Tabla 29. Código GRUB parte 5. .................................................................... 131 Tabla 30. Código GRUB parte 6. .................................................................... 136 Tabla 31. Código GRUB parte 7. .................................................................... 137 Tabla 32. Código GRUB parte 8. .................................................................... 138 Tabla 33. Código GRUB parte 9. .................................................................... 141 Tabla 34. Código GRUB parte 10. .................................................................. 143 Tabla 35. Firma Código GRUB parte 11. ........................................................ 144 XIV RESUMEN ESTUDIO, DESARROLLO E IMPLEMENTACIÓN DE UN GESTOR DE ARRANQUE PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL Las computadoras que al encender inician en modo real realizan un proceso denominado POST (Power On Selft) que se encarga de verificar que el hardware de la pc esté funcionando correctamente, almacene en memoria las interrupciones de la BIOS (Basic Input/Output System), busque un dispositivo de arranque (disco duro, disquetera, DVD, etc.), cargue a memoria su código de arranque y otorgue el procesamiento de la pc dicho código es denominado MBR (Master Boot Record). Los gestores de arranque que son los que tiene el código del MBR como un módulo, inyectan el MBR en los dispositivos de almacenamiento (Disco duros, cds, dvs etc.), convirtiéndoles así en dispositivos de arranque. El presente proyecto pretende dar una visión general de cómo funciona un gestor de arranque, que es necesario para que la pc pueda reconocer un dispositivo de arranque, entender como el código del MBR es desarrollado en lenguaje ensamblador y lenguaje c, como este es transformado a lenguaje de máquina, como este es entendido y ejecutado por la pc. Tener un entendimiento de cómo interactúa el hardware y el software del gestor de arranque para dotarle a la máquina de “inteligencia”. Se realizará un estudio de los gestores de arranque NTLDR y GRUB LEGACY, se modificará y construirá GRUB LEGACY y se desarrollará un MBR propio. DESCRIPTORES: LENGUAJE ENSAMBLADOR / LENGUAJE C / BOOTLOADER / GESTOR DE ARRANQUE / GRUB / GCC. XV ABSTRACT STUDY, DEVELOPMENT AND IMPLEMENTATION OF A MANAGER OF STARTING TO COMPUTERS X86 PC COMPATIBLE TO BEGIN IN REAL MODE. Computers that start in real mode perform a process called POST (Power On Selft) responsible of verifying that the pc hardware is works properly, loads into memory the interruptions of BIOS (Basic Input / Output System), searches a boot device (hard drive, floppy drive, DVD, etc.), loads memory boot code and grants processing of the pc, this code is so-called MBR (Master Boot Record). The bootloaders; which have the MBR code as a module, they inject the MBR into of the storage devices (hard disk, CDs, dvs etc.) making them become bootloaders. The aim of the present project is to give an overview about how a bootloader works; which is necessary for the PC to recognize a boot device, understand how the MBR code is developed in assembly language and C language; as this transformed into machine language; as this is understood and executed by the pc. Having an understanding of how the hardware and software of the boot loader interact in order to provide to the machine "intelligence". A study about NTLDR, GRUB LEGACY, will be implemented, GRUB LEGACY will be modified and built, and new MBR well be developed. DESCRIPTORS: ASSEMBLY LANGUAGE / LANGUAGE C / Bootloader / MANAGER START / GRU / GCC. XVI CERTIFICADO DE TRADUCCIÓN Quito 04 de Abril del 2105 CERTIFICADO DE TRADUCCIÓN EL M. Sc. IZA PIARPUEZAN CARLOS EDUARDO, identificado con cedula de ciudanía 1719197764, con título de tercer nivel en LICENCIADA EN CIENCIAS DE LA EDUCACIÓN MENCIÓN INGLES, de la Universidad Central del Ecuador. CERTIFICA: Que el documento anexo del resumen del tema de tesis denominado: ESTUDIO, DESARROLLO E IMPLEMENTACIÓN DE UN GESTOR DE ARRANQUE PARA COMPUTADORAS PC COMPATIBLES X86 QUE INICIAN EN MODO REAL, redactado en idioma español es traducción fiel y completa al idioma inglés. El interesado puede hacer uso del presente documento conforme lo considere necesario. Atentamente M. Sc. IZA PIARPUEZAN CARLOS EDUARDO. XVII TÍTULO DEL TRADUCTOR XVIII INTRODUCCIÓN Los gestores de arranque son los encargados de iniciar un determinado Sistema Operativo ya sea propietario o software libre, es decir es el primer fragmento de código que la computadora lee y ejecuta desde un dispositivo de arranque. La mayoría de gestores de arranque se dividen en dos etapas. La primera etapa consiste en un fragmento de código la mayoría de veces escrito en lenguaje ensamblador que debe ocupar un tamaño exacto de 512 bytes cuyos bytes 511, 512 deben ser 0x55 y 0xAA respectivamente, la principal función de la primera etapa es buscar, cargar a memoria la segunda etapa y ceder el procesamiento de la pc a esta. La segunda etapa es cargada y cedida el procesamiento de la pc por la primera etapa, la principal función de la segunda etapa es encontrar el kernel del Sistema Operativo que se desea iniciar, cargarlo a memoria y transferir el procesamiento de la pc a este. El presente documento da a conocer el estudio, desarrollo, alcance e implementación de un gestor de arranque para computadoras pc compatibles x86 que inician en modo real. El principal objetivo del presente trabajo de investigación es modificar el código de un gestor de arranque de software libre, entender su funcionamiento y desarrollar un gestor de arranque para computadoras pc compatibles x86. Para lo cual se realizara un estudio de los principales gestores de arranque en la actualidad, su estructura lógica y física, como son cargados a memoria, como son ejecutados por la BIOS al prender el computador, como se comunican con el hardware y como inician un determinado sistema operativo. 1 CAPITULO 1 1. PRESENTACION DEL PROBLEMA 1.1 Planteamiento del Problema Sin un software una computadora es una máquina inservible que tiene partes electrónicas y mecánicas interconectadas, El software es la parte fundamental de la llamada “inteligencia” de las computadoras. El software es el que le proporciona la capacidad de almacenar información correctamente ordenada para su posterior uso. Los algoritmos de software del sistema operativo mantienen toda la complejidad de manejo del hardware de la pc alejado de las aplicaciones que sobre él se ejecutan. El principal software de una computadora es el Sistema Operativo ya que este es el encargado de gestionar, planificar, asegurar el correcto funcionamiento de las aplicaciones que sobre el corren. Los sistemas operativos no dan ninguna funcionalidad al usuario final motivo por el cual no genera valor. Pero los sistemas Operativos permite que las aplicaciones que el usuario final utiliza se ejecuten creando así dependencia del Sistema Operativo. Los gestores de arranque son los encargados de crear un código denominado bootloader que es inyectado en los dispositivos de almacenamiento para que cuando la pc encienda cargue a memoria el bootloader, el bootloader tiene por objetivo encontrar el kernel del sistema operativo descomprimirlo cargarlo a memoria y pasarle el control de la pc. Así el primer código que dota de “inteligencia” al computador es un gestor de arranque. Todo Sistema Operativo tiene una organización o autor que desarrollo dicho Sistema Operativo, como por ejemplo en el caso de Unix cuyo propietario es la compañía AT&T. En la década de 1970 Unix se puso a disposición de Universidades, Compañías y al gobierno de EEUU por medio de licencias, las 2 cuales permitían a los investigadores revisar el código fuente de Unix. Hasta en 1977 la Universidad de Berkeley desarrollo, público y licencio un sistema operativo muy parecido a Unix, el cual fue nombrado Berkeley Software Distribution (BSD), que represento una notable competencia para UNIX. AT&T percatándose de lo riesgoso que es ofrecer el código UNIX para investigación decide a partir de la v7, restringir este beneficio. Así los investigadores del código de UNIX ya tenían prohibido su revisión. Andrew S. Tanenbaum que impartía clases de Sistemas Operativos en la Universidad Libre de Ámsterdam, en vista de que ya no podía dar clases impartiendo el código fuente de UNIX desarrollo un nuevo sistema operativo al cual nombro MINIX por ser un clon de Unix pero mucho más pequeño para que sus alumnos lo puedan entender en el transcurso de un semestre. Este hecho nos indica que cualquier software por más licencias de código libre que tenga, estas puedes hacerse más restrictivas, privando así a los investigadores de los código fuente estudiar la estructura del software, proponer cambios, mejoras etc. Contextualización El estudio, modificación y desarrollo de un gestor de arranque deja un entendimiento claro de cómo el código fuente de un programa es transformado a lenguaje maquina o binario y como este da funcionalidad a las partes de la computadora en cada ciclo de reloj de la pc. La manera más segura de dejar de depender de Sistemas Operativos desarrollados en otros países es desarrollar un sistema operativo propio y este debe estar en constante evolución por parte de una institución educativa como la Universidad Central del Ecuador, o de una empresa puramente ecuatoriana, solo así seremos independientes al menos en lo que respecta al software. 3 1.2 Formulación del Problema ¿Cuál es la ventaja de desarrollar el Proyecto de Estudio, Desarrollo E Implementación De Un Gestor De Arranque Para Computadoras Pc Compatibles X86 Que Inician En Modo Real? 1.3 Justificación Las principales industria del software venden o dan soporte a aplicaciones que se ejecutan en un determinado sistema operativo, creando así negocio para la aplicación que están ofreciendo y dependencia de su sistema operativo. Un sistema operativo es iniciado por un gestor de arranque que es el responsable de descomprimirle cargarlo a memoria y cederle el control de la pc. Los gestores de arranque propietarios o de software libre están en continua evolución. Una vez que el código fuente base ya no se adecua al hardware nuevo se vuelve a rescribir todo el código como es el caso de GRUB, gestor de arranque más utilizado por las distribuciones Linux. La manera de crear independencia en software es desarrollar un sistema operativo y por ende el gestor de arranque que lo inicia. El desarrollo del presente trabajo de fin de carrera permitirá aportar a la comunidad a través del sitio web http://www.softwaredesarrollo.com/, software de gestor de arranque en su formato binario, cuyo código será libre y documentado técnicamente, además se facilitara el proceso que se llevó a cabo y las herramientas de software libre que se utilizaran para la construcción del gestor de arranque. Se aportara a través del sitio web http://www.softwaredesarrollo.com/, como se logró modificar el gestor de arranque GRUB, indicando el proceso que se utilizó y las herramientas en software libres ocupadas. 4 La importancia del presente trabajo de tesis radica en dar a conocer la importancia de los gestores de arranque al iniciar la pc, y demostrar que su complejidad se la puede investigar con los conocimientos obtenidos en la carrera de Ingeniería Informática, proporcionando así más documentación y herramientas a las personas que deseen realizar una investigación sobre los gestores de arranque. 1.4 Objetivos de la Investigación 1.4.1 Objetivo General Modificar y desarrollar un software de gestor de arranque para computadoras pc compatibles x86 que inician en modo real. 1.4.2 Objetivos Específicos Poner a disposición de la comunidad, software de un gestor de arranque documentado, las herramientas necesarias para su construcción, ejecución con el objetivo de facilitar su estudio, mejora y solución de errores etc. A través del sitio web www.softwaredesarrollo.com. Realizar un estudio de los principales gestores de arranque que existen en el mercado. Modificar un gestor de arranque de software libre. Desarrollar un gestor de arranque básico. Difundir la importancia de crear gestores de arranque y sistemas operativos a nivel de un país. 5 1.6 Alcance La investigación y desarrollo del presente tema de fin de carrera tiene el siguiente alcance: Investigar el funcionamiento lógico y práctico del gestor de arranque GRUB LEGACY, su código fuente y el software necesario para su construcción y ejecución. Indicar la importancia de desarrollar software a nivel de lenguaje ensamblador para la creación y modificación de gestores de arranque. Modificar el gestor de arranque GRUB LEGALICY, indicar el proceso y las herramientas necesarias para su modificación, así también las herramientas necesarias para procesar, ensamblar y enlazar el software modificado. Crear un software de gestor de arranque básico. El gestor de arranque está restringido a pc compatibles x86 que inician en modo real. El gestor de arranque podrá ejecutarse a través del disco duro, CD y Usb. Diseñar, desarrollar e implementar el sitio web www.softwaredesarrollo.com. Poner a disposición de la comunidad toda la documentación y software libre que se genere del desarrollo del tema de fin de carrera a través del sitio web www.softwaredesarrollo.com. 6 1.7 Limitaciones Para la investigación y desarrollo del presente tema de tesis se presentaron las siguientes limitaciones: No se tiene documentación, código de los gestores de arranque propietarios. Utilizar las librerías de GNU GCC para compilar los programas desarrollados en lenguaje en ensamblador y lenguaje c. Se tuvieron que emplear herramientas de software libre de ingeniería inversa para investigar la estructura de los gestores de arranque de código propietario. Al utilizar herramientas de software libre se tiene el inconveniente de no con contar con suficiente documentación para la modificación y construcción del gestor de arranque, lo cual demora su investigación y construcción. Se contrató un web hosting en una empresa privada para aportar a la comunidad el trabajo desarrollado. 7 1.8 Contribuciones Las contribuciones que se lograría al desarrollar el presente tema de fin de carrera son: Aportar a la comunidad la importancia de crear software que se pueda ejecutar sin la necesidad de un sistema operativo. Aportar como se logró modificar el gestor de arranque más utilizado por las distribuciones Linux su reconstrucción y ejecución en este caso GRUB LEGACY. Aportar a la comunidad el sitio web www.softwaredesarrollo.com. Diseñado, desarrollado e implementado por el autor del tema de fin de carrera. A través del sitio web www.softwaredesarrollo.com, la comunidad podrá descargar el software y documentación que se genere del desarrollo del tema de fin de carrera. Aportar con código fuente, técnicamente documentado, de libre descarga, modificación y ejecución. Proporcionar las herramientas en software libre y el proceso que se realizó para la construcción del gestor de arranque. Aportar como guía de aprendizaje para todos aquellos programadores que deseen introducirse el desarrollo de bajo nivel, y su combinación con lenguaje c. 8 1.9 Herramientas Para el desarrollo modificación e investigación sobre los gestores de arranque son necesarias las siguientes herramientas en software y hardware: 1. Hardware Computador PC de 64 bits 2. Software Sistema operativos host i. Windows 7 de 64 bits. Máquina Virtual i. Virtual Box ii. Bochs iii. Quemu Sistemas operativos huéspedes i. Windows 98. ii. Windows Xp de 32 bits iii. Windows 7 de 64 bits iv. Linux Centos de 32 bits v. Linux Centos de 64 bits vi. Linux Fedora Aplicaciones i. Gnu gcc diferentes versiones ii. HexEdit 32 y 64 bits iii. Nasm iv. Alink v. Gnu as vi. Gnu link 9 CAPITULO 2 2. MARCO METODOLÓGICO 2.1 Diseño de la Investigación El presente trabajo de fin de carrera desea implementar la importancia de generar un gestor de arranque y un sistema operativo a nivel de universidad, tomando como caso de uso la historia y evolución de los sistemas operativos sus gestores de arranque, la gran dependencia que genera un sistema operativo para el usuario final de una pc. La investigación a realizar en este proyecto es una investigación experimental que va permitir por medio de la manipulación del código del gestor de arranque de software libre GRUB investigar su funcionamiento, lo cual generará experiencia y documentación. Con el conocimiento obtenido procederemos a desarrollar un prototipo de un gestor de arranque desde cero. La documentación técnica y de usuario que se generará será puesta a disposición de la comunidad a través del sitio web www.softwaredesarrollo.com el cual es desarrollado y administrado por el autor del tema de tesis, la comunidad interesada puede estudiar, ofrecer mejoras, cambios etc. Asi logrando conocimiento y el interés por desarrollar software a bajo nivel y desarrollo de sistemas operativos. Para el desarrollo y la implementación del diseño de la investigación se deben estudiar los siguientes hechos y la siguiente teoría. Con el fin de profundizar en el tema y tener argumentos que respalden las decisiones tomadas en el presente tema de tesis. 10 2.2 Antecedentes Los gestores de arranque aparecen con el desarrollo de los sistemas operativos ya que el gestor de arranque es el encargado de ejecutar un determinado sistema operativo cuando se inicia el encendido de la computadora. El gestor de arranque no es parte del sistema operativo, este el encargado de cargar a memoria el kernel del sistema operativo. Una vez cargado el kernel el sistema operativo no utiliza ninguna librería del gestor de arranque para su continuo funcionamiento. Los gestores de arranque han evolucionado conforme evolucionaron los sistemas operativos, pero los gestores de arranque siguen iniciando su ejecución en modo real para tener compatibilidad con hardware antiguo. Existen varios gestores de arranque en el mercado entre los más principales tenemos: GRUB, LILO.- Gestores de arranque de Linux están bajo licencia GNU GPLv3 y BSD respectivamente. NTLDR.- Gestor de arranque de Windows, bajo licencia de Microsoft. BOOTX (Apple).- Gestor de arranque de Mac OSX, bajo licencia de Apple. Al investigar los gestores de arranque se comprenderá el funcionamiento interno del computador y los concepto de BIOS, hardware, memoria procesador, sistemas de archivos, disco duro, tarjeta de video, pixeles, sistema de numeración binaria, hexadecimal y decimal, así como la comunicación entre los distintos dispositivos de la PC, lenguaje ensamblador y lenguaje C. 11 2.3 Fundamentación Teórica A continuación se presenta la fundamentación teórica y las herramientas de software libre que se requieren para la investigación, modificación y desarrollo de un gestor de arranque. 2.3.1 Evolución De Los Sistemas Operativos y Computadores Los sistemas operativos dan la plataforma para que las aplicaciones finales de usuario se puedan ejecutar, es decir ocultan la parte fea con la parte hermosa, como se muestra en la figura 1. Figura 1. Abstracción de Interfaz Aplicaciones y S.O. Autor: Andrew S. Tanenbaum. Fuente: Sistemas Operativos Modernos 3ra edición. Los sistemas operativos han estado estrechamente relacionados a través de la historia con la arquitectura de las computadoras en las que se ejecutan. La primera computadora digital verdadera fue diseñada por el matemático inglés Charles Babbage, la cual nunca logró funcionar de manera apropiada, debido a que era puramente mecánica y la tecnología de su era no podía producir las ruedas, engranes y dientes con la alta precisión que requería. La máquina analítica no tenía un sistema operativo. 12 2.3.1.1 Primera Generación (1946-1958) En esta época las computadoras eran sumamente grandes, utilizaban gran cantidad de electricidad, generaban gran cantidad de calor y eran sumamente lentas. Funcionaban con válvulas de vacio, usaban tarjetas perforadas para ingresar los datos y los programas, utilizaban cilindros magnéticos para almacenar información e instrucciones internas y se utilizaban exclusivamente en el ámbito científico o militar. La programación implicaba la modificación directa de los cartuchos, 2.3.1.2 Segunda Generación (1955 a 1965) Las computadoras usaban transistores para procesar información, usaban pequeños anillos magnéticos para almacenar información e instrucciones. Producían gran cantidad de calor y eran sumamente lentas. Se mejoraron los programas de computadoras que fueron desarrollados durante la primera generación. Se desarrollaron nuevos lenguajes de programación como COBOL y FORTRAN, los cuales eran comercialmente accesibles. Y se desarrolló el sistema de procesamiento por lotes. Figura 2. Procesamiento por Lotes Autor: Andrew S. Tanenbaum. Fuente: Sistemas Operativos, Diseño e implementación 2da edición. En la segunda generación las maquinas no tenían sistemas operativos. 13 2.3.1.3 Tercera Generación (1965 a 1980) Comienza a utilizarse los circuitos integrados, lo cual permitió abaratar costos al tiempo que se aumentaba la capacidad de procesamiento y se reducía el tamaño de las máquinas. La tercera generación de computadoras emergió con el desarrollo de circuitos integrados (pastillas de silicio) en las que se colocan miles de componentes electrónicos en una integración en miniatura. El PDP-8 de la Digital Equipment Corporation fue el primer miniordenador. Se diseñó el sistema conocido como MULTICS (MULTiplexed Information and Computing Service, Servicio de Información y Cómputo MULTiplexado), fue un éxito parcial. Se diseñó para dar soporte a cientos de usuarios en una máquina que era sólo un poco más potente que una PC basada en el Intel 386. Posteriormente, Ken Thompson, uno de los científicos de cómputo en Bell Labs que trabajó en el proyecto MULTICS, encontró una pequeña minicomputadora PDP-7 que nadie estaba usando y se dispuso a escribir una versión simple de MULTICS para un solo usuario. Más adelante, este trabajo se convirtió en el sistema operativo UNIX, que se hizo popular en el mundo académico, las agencias gubernamentales y muchas compañías. 2.3.1.4 Cuarta Generación (1965 a 1980) Está caracterizada por la integración sobre los componentes electrónicos, lo que propició la aparición del microprocesador, es decir un único circuito integrado en el que se reúnen los elementos básicos de la máquina. Se desarrolló el microprocesador con micro compactación. Se colocan más circuitos dentro de un "chip". "LSI - Large Scale Integration circuit". "VLSI - Very Large Scale Integration circuit". Cada "chip" puede hacer diferentes tareas. Un "chip" sencillo actualmente contiene la unidad de control y la unidad de aritmética/lógica. El tercer componente, la memoria primaria, es operado por otros "chips". Se reemplaza la memoria de anillos magnéticos por la memoria de "chips" de silicio. Se desarrollan las microcomputadoras, computadoras personales o PC. Tambien se desarrollan las supercomputadoras. 14 2.3.1.5 Historia Hechos Relevantes Cuando Intel presentó el microprocesador 8080 en 1974, pidió a uno de sus consultores, Gary Kildall, que escribiera un sistema operativo para dicho procesador. Kildall escribió un sistema operativo basado en disco conocido como CP/M (Control Program for Microcomputers; Programa de Control para Microcomputadoras) Kildall compro los derechos de CP/M. y formó una compañía llamada Digital Research para desarrollar y vender el CP/M. Se escribieron muchos programas de aplicación para ejecutarse en CP/M, lo cual le permitió dominar por completo el mundo de la micro computación durante un tiempo aproximado de 5 años. A principios de la década de 1980, IBM diseñó la IBM PC, y busco un sistema operativo, contactaron con Bill Gates y Gary Kildall, terminaron negociando con Bill Gates, y el fundo Microsoft con el sistema operativo MS-DOS, posteriormente se fueron dando evoluciones apareciendo Windows 95, Milinium, XP, Windows 7 etc. Andrew´s Tanenbaum viéndose limitado por el cambio del licencia de AT&T de no poder enseñar su código, en 1987 libera un clon de UNIX llamado MINIX el cual tiene un objetivo puramente educacional. El deseo de una versión de producción (en vez de educativa) gratuita de MINIX llevó al estudiante finlandés, llamado Linus Torvalds, a escribir Linux. Este sistema estaba inspirado por MINIX, además de que fue desarrollado en este sistema y originalmente ofrecía soporte para varias características de MINIX (por ejemplo, el sistema de archivos de MINIX). Linus Tolvards y la organización FFS (Free Software Foundation) de Richard Stallman se fusionan y se desarrolla el sistema operativo conocido como GNU Linux. 15 2.3.2 Microprocesador 2.3.2.1 Concepto Es un circuito electrónico sumamente integrado que actúa como unidad central de proceso de un ordenador. El microprocesador ejecuta instrucciones almacenadas como números binarios organizados secuencialmente en la memoria principal. La ejecución de las instrucciones se puede realizar en varias fases. Cada una de estas fases se realiza en uno o varios ciclos de CPU, dependiendo de la estructura del procesador y concretamente de su grado de segmentación. La duración de estos ciclos viene determinada por la frecuencia de reloj y nunca podrá ser inferior al tiempo requerido para realizar la tarea individual. 2.3.2.2 Evolución del microprocesador Los microprocesadores nacieron de la evolución de los circuitos integrados. 1971: El Intel 4004 El 4004 fue el primer microprocesador del mundo en un simple chip, fue desarrollado por Intel. Era un CPU de 4 bits y también fue el primero disponible comercialmente. Originalmente diseñado para la compañía japonesa Busicom para ser usado en su línea de calculadoras, dio camino a la manera para dotar de «inteligencia» a objetos inanimados, así como la computadora personal. Microprocesador Año Fabricante 4004 1971 Intel 8086 AMD, Harris, Mostek, Fujitsu, 1978 NEC, Toshiba, OKI, Siemens 80286 1982 80386 1985 Intel AMD, Harris, IBM, Siemens Bits Pins Clock Caracteristicas 4 16-dip .1MHz Primer Microprocesador 16 40 510MHz Primer 16-bit CPU; 8088 (1979); IBM PC (1981) 16 68LCC/PGA 6 MHZ20MHz 32 132-PGA 1633MHz 16 Soporta Memoria Virtual; IBM PC AT (1984) Primer 32-bit CPU; Cache; Multitarea Microprocesador 80486 Año 1989 Fabricante Intel Bits Pins 32 16PGA,176TQFP Clock 100MHz Pentium 1993 Intel 32 273PGA,320TCP 60MH233Mhz Pentium II 1997 Intel 32 528-LGA, 615BGA 233MH500Mhz Pentium III 1999 Intel 32 370-PGA2, 495BGA2 400M1Ghz Pentium 4 2000 Intel 32 423-PGA, 478PGA 1.52Ghz Multi Core 2006 Intel 64 479-775 1-3Ghz i3,i5,i7 2008 INTEL 64 437-1366 1.6 3.5Ghz Athlon Sempron64 2011 AMD 64 939 2800+ hasta 3600 Athlon 64 2011 AMD 64 939 3000+ hasta 3800 Athlon 64 con Socket AM2 2011 AMD 64 939 3200+ y 3800 Athlon 64 X2 2011 AMD 64 939 3800+h asta 4800 Caracteristicas Cache nivel L1 Superscalar: 2IU, 1-FPU; MMX (1995) RISC 2-IU,2FPU,3-LDST, 2MMX; Xeon, Celeron 2-IU,2-FPU,3LDST, 2-MMX, 2SSE; Mobile (M) HT (2002); 4M (2003); Xeon MP (2003); Centrino (2003) D (2005); Core 2 (2006); Dual Core (2006); Quad Core (2007) i7-920 (2008): 4 cores; i7-980 (2011): 6 cores Athlon Sempron64 con socket AM2 Athlon 64 con Socket 939, Nucleos Venice y Manchester Athlon 64 con Socket AM2. Athlon 64 X2 con Socket 939, dos micros en en el mismo espacio, Tenemos dos núcleos: Manchester, Toledo Tabla 1. Evolución De Los Microprocesadores. Autor: Tesista Fuentes: http://www.wadalbertia.org/docs/EvolucionProcesadoresIntel.pdf. http://www.intel.la/content/www/xl/es/homepage.html. 17 2.3.2.3 Arquitectura El microprocesador se compone de un grupo de unidades interrelacionadas como se muestra en la figura 3. Aunque la arquitectura del microprocesador varía considerablemente de un diseño a otro, el diseño se basa en la arquitectura del microprocesador 8086. Figura 3. Arquitectura de Microprocesador o CPU 8086. Autor: Tesista. Fuente: http://es.wikipedia.org/wiki/Intel_8086_y_8088. 18 2.3.2.4 Registros En la siguiente tabla se muestran los registros del procesador 8086, su número, tamaño y su uso común en la programación. Tipo de registro De propósito general De segmento Apuntador de instrucción Apuntadores Número y tamaño 4 registros de 16 bits 4 registros de 16 bits 1 registro de 32 bits 4 registros de 16 bits Descripción Almacenan datos. Para uso del programador Permiten direccionar la memoria Apunta a la siguiente instrucción a ejecutar Se usan para direccionar memoria. Tabla 2. Registros del Microprocesador 80386. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. Registros de Propósito General: Los registros de propósito general AX, BX, CX y DX son los únicos que se pueden direccionar como una palabra o como una parte de un byte. El último byte de la izquierda es la parte "alta", y el último byte de la derecha es la parte "baja". Registro ax bx cx dx Descripción Acumulador para operaciones aritmético lógicas Registro base para acceder a memoria Contador para algunas instrucciones Registro de datos usado para algunas operaciones de entrada/salida Tabla 3. Uso común de los registros de propósito general. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. Registros de Segmento: Se utilizan para referenciar áreas de memoria. La siguiente tabla muestra los registros de segmento de los microprocesadores compatibles x86 y su uso en la programación. Registro de segmento cs ds ss es fs Descripción Segmento de código Segmento de datos Segmento de pila segmento extra segmento extra Tabla 4. Uso común de los registros de segmento. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. 19 El contenido de los registros de segmento es interpretado de diferente forma dependiendo si el procesador se encuentra trabajando en modo real o en modo protegido. Registros Apuntadores: La función común de los registros apuntadores es contener la dirección de memoria de una estructura de datos o código, ya sea para acceder a un elemento de la estructura, también como apuntador de base inicial o final de la estructura en memoria. Registro ip di si sp bp Descripción Apuntador de instrucción o contador de programa Apuntador a destino para operaciones con cadenas de caracteres Apuntador a origen para operaciones con cadenas de caracteres Apuntador de pila Apuntador de marco o base de pila Tabla 5. Registros apuntadores del microprocesador. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. Entre los registros apuntadores el más principal es el apuntador de instrucción o contador de programa. Registro IP o Contador de Programa: Es un registro que almacena la dirección donde se encuentra la siguiente instrucción del programa a ejecutar. La unidad de control va incrementando el valor de este registro a medida que recupera instrucciones y los operandos asociados. También lo modifica cuando se ejecuta un salto, condicional o incondicional, estableciendo la nueva dirección de la que se recuperarán los códigos de instrucción. Registro SI (source index): El registro índice fuente de 16 bits es requerido por algunas operaciones con cadenas de caracteres. Registro DI (destination index): El registro índice destino (destination index) también es requerido por algunas operaciones con cadenas de caracteres. 20 Registro SP (stack pointer): El apuntador de pila de 16 bits está asociado con el segmento SS y proporciona un valor de desplazamiento que se refiere a la palabra actual que está siendo procesada en la pila. Registro BP (base pointer): El apuntador base de 16 bits facilita la referencia de parámetros dentro de la pila. Banderas: Proveen una manera de obtener información acerca del estado actual de la máquina y el resultado de procesamiento de una instrucción. Bandera CF PF AF ZF SF TF IF DF OF Bit 0 2 4 6 7 8 9 10 11 Descripción Bandera de acarreo (carry flag) Bandera de paridad (parity flag) Bandera de acarreo auxiliar (adjust flag) Bandera de cero (zero flag) Bandera de signo (sign flag) Bandera de depuración(trap flag) Bandera de Interrupcion(interruption flag) Bandera de dirección (direction flag) Bandera de desbordamiento (overflow flag) Tabla 6. Banderas del microprocesador. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. CF (carry flag): Después de una operación aritmética contiene el acarreo del bit de mayor orden, también almacena el contenido del último bit en una operación de desplazamiento o de rotación, es decir se activa en un uno cuando existe acarreo después de una operación aritmética. PF (parity flag): Indica si el número de bits 1 despues de una operación es par (0=número de bits 1 es impar; 1=número de bits 1 es par). AF (adjust flag): Se pone a 1 si se produce un acarreo entre los bits 7 y 8 trabajando con 16 bits o entre los bits 3 y 4 trabajando con 8 bits. Se utiliza para ajustes decimales en operaciones en BCD. ZF (zero flag): Se pone a 1 cuando el resultado de la última operación es cero, o cuando al comparar dos cadenas el resultado es de igualdad. 21 SF (sign flag): Se pone a 1 si el resultado es negativo, o cuando al comparar dos cadenas, el resultado es de no igualdad. TF (trap flag): Permite la operación del procesador en modo de depuración (paso a paso). IF (interruption flag): Controla el disparo de las interrupciones (1=habilita las interrupciones; 0=deshabilita las interrupciones). La interrupción no enmascarable es la única que no puede ser bloqueada por esta bandera. El estado de la bandera IF se controla con las instrucciones STI y CLI. DF (direction flag): Controla la selección de incremento o decremento de los registros SI y DI en las operaciones con cadenas de caracteres (1=decremento automático; 0=incremento). La bandera DF se controla con las instrucciones STD y CLD. OF (overflow, desbordamiento): Indica desbordamiento del bit de mayor orden después de una operación aritmética de números con signo (1=existe overflow; 0=no existe overflow). Para operaciones sin signo, no se toma en cuenta esta bandera. 2.3.2.5 Unidad aritmética lógica Es el elemento que lleva a cabo las operaciones aritméticas, como suma, resta y lógicas al nivel de bits según el álgebra de Boole. En la mayoría de los casos la ALU (Arithmetic Logic Unit) asume como operando implícito el dato almacenado en el acumulador pudiendo existir según la instrucción a ejecutar operandos adicionales. También influye en su funcionamiento el contenido del registro de estado. 22 Figura 4. Esquema de Bloques de una ALU Típica. Autor: Tesista. Fuente: Lenguaje ensamblador 2009 - Fco. Charte Ojeda pag 38. Sobre la base de esta arquitectura abstracta, cada fabricante lleva a cabo la arquitectura física de sus microprocesadores según parámetros reales: ancho de palabra, ancho del bus de direcciones, cantidad de registros internos, operaciones que pueda llevar a cabo la ALU, etc. Para ejecutar cada instrucción la CPU realiza los siguientes pasos: 1. Leer de la memoria la instrucción a ejecutar y guardarla en un registro interno de la CPU. 2. Identificar la instrucción que acaba de leer. 3. Comprobar si la instrucción necesita datos que se encuentran en memoria, si es el caso, determina la localización de los mismos. 4. Buscar los datos en memoria y guardarlos en registro dentro de la CPU. 5. Ejecutar la instrucción. 6. El resultado puede ser almacenado en memoria o retenido esperando la siguiente instrucción o incluso generar comunicación con otros elementos externos a la CPU. 7. Comienza un nuevo ciclo empezando con el primer paso. 23 2.3.3 Memoria La memoria es la parte del ordenador en la que se guardan o almacenan los programas (las instrucciones y los datos). Figura 5. Memoria Típica. Autor: Tesista. Fuente: http://www.cem-sa.com.mx/products-page/subensambles/ram/memoria-ram-2gbddr3-kingston-1333mhz-pc/ Los datos almacenados en memoria tienen que pasar, en un momento u otro, al microprocesador para que éste pueda servirse de ellos y, en caso necesario, manipularlos. La división de memorias entre primario, secundario, terciario, fuera de línea, se basa en la distancia desde la CPU a la memoria. 2.3.3.1 Tipos de Memoria A las memorias usadas en la pc se las puede clasificar en dos tipos básicos, la memoria RAM y la memoria ROM. 2.3.3.1.1 Memoria RAM La Memoria de Acceso Aleatorio (Random Access Memory) es una memoria construida sobre semiconductores donde la información se almacena en celdas de memoria que pueden adquirir uno de los dos valores del código binario. Las memorias de acceso aleatorio son memorias en la que se puede leer y escribir información. Permite el acceso a cualquier información que contenga 24 con la misma velocidad. Esto significa que se puede acceder aleatoriamente a cualquier información almacenada sin que se afecte la eficiencia del acceso. Requiere energía constante para mantener la información almacenada es decir sin energía pierde todos los datos. 2.3.3.1.1 Memoria ROM Memoria de solo lectura (read-only memory), utilizado en ordenadores y dispositivos electrónicos, que permite solo la lectura de la información y no su escritura, independientemente de la presencia o no de una fuente de energía. Los datos almacenados en la ROM no se pueden modificar, o al menos no de manera rápida o fácil. Sin embargo, las ROM más modernas, como EPROM y Flash EEPROM, efectivamente se pueden borrar y volver a programar varias veces, aun siendo descritos como "memoria de sólo lectura" (ROM). Retiene la información almacenada incluso si no recibe corriente eléctrica constantemente. La siguiente tabla muestra las características de las memorias usadas en una computadora. Tipo Memoria Random Access Memory (RAM) Read Only Memory (ROM) Programmable ROM (PROM) Propósito Memoria Lec/Esc Memoria de solo Lectura Erasable PROM (EPROM) Memoria Flash Electrically Erasable PROM (EEPROM) Memoria sobre todo de Lectura Borrado Eléctrico a nivel byte Modo de Escritura Eléctricamente Volatilidad Volátil Máscaras No Posible Luz UV a nivel chip Eléctrico a nivel bloque No Volátil Eléctricamente Eléctrico a nivel byte Tabla 7. Tipos de Memoria. Autor: Tesista. Fuente: Conocimientos adquiridos del tesista. 25 2.3.3.2 Memoria Principal La memoria principal en una computadora es una memoria de acceso aleatorio o RAM. Esta es la parte de la computadora que almacena software del sistema operativo, software de aplicaciones y otra información para la unidad central de procesamiento (CPU) y así tener acceso rápido y directo cuando sea necesario para realizar las tareas. Se llama "acceso aleatorio" porque la CPU puede acceder directamente a una sección de la memoria principal, y no debe emprender el proceso en un orden secuencial. La memoria principal es uno de los tipos de memoria más rápidas, y tiene la capacidad de permitir que los datos sean leídos, escritos y modificados. Cuando la computadora está apagada, todo el contenido almacenado en RAM se borra. La memoria principal está disponible en dos tipos: la memoria dinámica de acceso aleatorio (DRAM) y la memoria estática de acceso aleatorio (SRAM). 2.3.3.3 Arquitectura de la Memoria Principal La arquitectura de la memoria que se revisara es la de modo real, ya que esta es la forma de la memoria cuando inicia el funcionamiento de una pc. Figura 6. Arquitectura de la Memoria Principal. Autor: Pablo Turmero. Fuente: http://www.monografias.com/trabajos104/arquitectura-computadorasmemoria/arquitectura-computadoras-memoria.shtml. 26 Memoria Convencional Los primeros 640 Kb de la memoria del sistema constituyen la memoria convencional. Este es el área disponible para el uso de los programas DOS convencionales, junto con muchos controladores, programas residentes. Se encuentra en la dirección 00000h a 9FFFFh. Memoria Superior Está comprendida entre los 640 y los 1024 Kb, ocupando los últimos 384 Kb por encima de la memoria convencional y por debajo del primer Mb de memoria, por lo que se puede manejar de manera similar a la memoria convencional, puesto que está dentro del rango de direccionamiento del microprocesador. Está constituida por la RAM de video, Memoria Expandida y la Memoria Shadow o Rom BIOS. Bloque Memoria RAM de Video Es donde la imagen sobre la pantalla es almacenada en forma digital, con una unidad de memoria asignada a cada elemento de la imagen (bit, byte o bytes). El contenido entero de la memoria es leído de 44 a 75 veces en un segundo mientras se muestra la imagen sobre la pantalla del monitor. Mientras tanto la PC puede tratar de escribir una nueva imagen sobre la memoria. Bloque Memoria Expandida Este tipo de memoria se diseñó para los microprocesadores inferiores de la familia x86, es decir, los 8086/8088, cuyo diseño tiene limitado de forma absoluta el direccionamiento de más de 20 bits. La especificación inicial fue llamada LIM (Lotus/Intel/Microsoft), mediante la cual se permitía a cualquier PC el acceso hasta a un máximo de 4 megabytes que se vieron ampliados hasta 8 en la versión L1M 4.0. ¿Cómo puede un 8086/8088 direccionar esto? Muy simple: no puede. Por ello se utiliza un método bastante antiguo como es la paginación de la memoria. 27 En la paginación se dispone de varios bancos de memoria que se dividen en páginas de 16 kilobytes. Un circuito integrado especializado, como puede ser el PPI 8255, se encarga de intercambiar estas páginas, permitiendo ver al microprocesador sólo algunas de ellas en un determinado momento. Por lo tanto, el microprocesador sólo puede acceder a algunas de estas páginas, que se vuelcan en una determinada porción de memoria en el rango accesible por el microprocesador. En los sistemas DOS, este tipo de memoria se emplea mediante un controlador, llamado normalmente EMM.SYS, que añade un nuevo servicio a una de las interrupciones del DOS. Gracias a ella se puede acceder a esta memoria y establecer las páginas que deben estar activas en cada momento a través del marco de página. Bloque Memoria BIOS Espacio de BIOS en RAM se detalla más adelante. Memoria Extendida En el momento en que aparece el microprocesador 80286, con su capacidad para direccionar hasta 16 megabytes de memoria gracias al bus de 24 bits, nace la que se denomina memoria extendida. En un sistema 286 o superior que tenga más de un megabyte de memoria, ésta puede utilizarse directamente siempre que trabajemos en el modo nativo del microprocesador, no el de emulación 8086 o modo real. Pero hay un problema: el DOS no está preparado para utilizar este modo protegido y facilitar a las aplicaciones el uso de esa memoria. Soluciones: Consiste en utilizar un controlador que trate dicha memoria extendida como expandida, simulando las páginas y trabajando según el esquema descrito en el punto previo. Este método tiene la ventaja de permitir que funcionen 28 correctamente muchos programas que están preparados para funcionar utilizando memoria expandida. Pero es la única ventaja. La memoria extendida se puede dividir, a su vez, en varias categorías: memoria alta y memoria extendida propiamente dicha. Bloque Memoria alta Son los primeros 64 Kb, menos 16 bytes, del segundo Mb de la memoria de sistema. Técnicamente son los primeros 64 Kb de la memoria extendida. Suele ser usada por el DOS para preservar más memoria convencional. Ocupa las direcciones 100000h a 10FFEFh. Como se ha mencionado anteriormente el microprocesador 8086 dispone de un bus de direcciones de 20 bit, lo que le posibilita el acceso a 1 MB de memoria y sus registros son de 16 bits, por lo que puede acceder a direcciones en el rango de 216 bytes = 64 Kb, pero gracias al direccionamiento [segmento: dirección] podemos obtener una dirección lineal de 20 bits. Por lo tanto, toda la memoria por encima de la dirección FFFF: 000Fh no es accesible por medio de un direccionamiento inmediato, puesto que esta dirección equivale al punto lineal de 0FFFFh*10h+Fh = FFFFFh = 1048575d. Supongamos la dirección FFFF: 0010h equivalente al punto lineal 1048576d ya está en el rango de los 21 bits, lo que provocaría el desbordamiento del bus y su recorte al valor 0. Los microprocesadores más modernos ya cuentan con un bus de direcciones más grande, por ejemplo el 80286 con 24 bits está compuesto de 24 líneas: A0, A1, A2,..., A23, anuladas de la línea A20 en adelante para emular el modo real. Habilitar la línea A20 permite direccionar localidades en la HMA, puesto que evitaríamos el desbordamiento al acceder a más de 1 MB. Desde el MS-DOS 5.0 podemos elegir el ubicar su motor en la HMA, liberando espacio de la memoria convencional para nuestro uso. 29 2.3.4 Manejo de Memoria Todos los pc en la actualidad al iniciar su funcionamiento están en modo real lo que es decir se ejecutan como un microprocesador 8086 con todos sus limitantes de gestión de memoria. 2.3.4.1 Segmentación Los microprocesador 8086, cuenta externamente con 20 líneas de direcciones, con lo cual puede direccionar hasta 1 MB (00000h--FFFFFh) de localidades de memoria. En los días en los que este microprocesador fue diseñado, alcanzar 1 MB de direcciones de memoria era algo extraordinario, sólo que existía un problema, internamente todos los registros del microprocesador tenian una longitud de 16 bits, con lo cual sólo se pueden direccionar 64 KB de localidades de memoria. Resulta obvio que con este diseño se desperdicia una gran cantidad de espacio de almacenamiento, la solución a este problema fue la segmentación. La segmentación consiste en dividir la memoria de la computadora en segmentos. Un segmento es un grupo de localidades con una longitud mínima de 16 bytes y máxima de 64 KB. A cada uno de estos segmentos se le asigna una dirección inicial y ésta es almacenada en los registros de segmento correspondiente, CS para el código, DS para los datos, ES para el segmento extra y SS para la pila. De esta forma, si un programa intentaba acceder a un dato ubicado en el desplazamiento „D‟ del segmento apuntado por el registro ds, la traducción a una dirección lineal consistía en tomar el contenido de dicho registro, multiplicarlo por 0x10 y sumarle el desplazamiento „D‟. 30 Figura 7. Segmentación de Memoria Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/regseg.html. En el modo protegido, el registro de segmento ya no contiene la dirección base del segmento, sino un selector de segmento, el cual permite seleccionar un descriptor de segmento. EL descriptor de segmento no es más que una estructura de ocho bytes, la cual posee un formato definido y contiene entre otras cosas la dirección base del segmento en cuestión. Existen otros métodos de gestión de memoria con los microprocesadores actuales como el manejo de memoria lineal, paginación, paginación segmentada etc. Estos métodos salen del ámbito de la investigación. 2.3.4.2 Direccionamiento La capacidad de direccionamiento de un microprocesador viene determinada directamente por el tamaño de los registros encargados de mantener las direcciones de memoria y su bus de direcciones. En el caso de los procesadores x86 éstos son los registros de segmento y otros que se usan como desplazamiento sobre ese segmento. Los primeros procesadores de la familia x86, concretamente el 8086 y 8088, eran microprocesadores de 16 bits, con registros de 16 bits para el direccionamiento. 31 Esto en principio limitaría la cantidad de memoria a la que se puede acceder a 64 Kbyte, lo cual era una limitación. La solución a este problema fue con la utilización combinada de dos registros, uno de segmento y otro de desplazamiento, para acceder a una mayor cantidad de memoria. 2.3.4.3 Modos de Direccionamiento Los llamados modos de direccionamiento son las diferentes maneras de especificar en informática un operando dentro de una instrucción. Cómo se especifican e interpretan las direcciones de memoria según las instrucciones. Un modo de direccionamiento especifica la forma de calcular la dirección de memoria efectiva de un operando mediante el uso de la información contenida en registros y / o constantes, contenida dentro de una instrucción de la máquina o en otra parte El tipo de direccionamiento esta en función de los operandos de la instrucción. Direccionamiento de registro Direccionamiento inmediato Direccionamiento directo Direccionamiento indirecto mediante registro Direccionamiento indirecto por registro base Direccionamiento indexado Direccionamiento indexado respecto a una base Direccionamiento de Registro Cuando ambos operando son un registro. Ejemplo: MOV AX, BX Transfiere el contenido de BX en AX Direccionamiento Inmediato Cuando el operando origen es una constante. 32 Ejemplo: MOV AX, 500 Carga en AX el valor 500. Direccionamiento Directo Cuando el operando es una dirección de memoria. Ésta puede ser especificada con su valor entre [ ], o bien mediante una variable definida previamente. Ejemplo: MOV BX, [1000] Almacena en BX el contenido de la dirección de memoria DS: 1000. MOV AX, TABLA Almacena en AX el contenido de la dirección de memoria DS: TABLA. Figura 8. Direccionamiento Directo. Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/regseg.html. Direccionamiento indirecto mediante registro Cuando el operando está en memoria en una posición contenida en un registro (BX, BP, SI o DI). Ejemplo: MOV AX, [BX] Almacena en AX el contenido de la dirección de memoria DS: [BX] 33 Figura 9. Direccionamiento indirecto mediante registro. Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/regseg.html. MOV [BP], CX Almacena en la dirección apuntada por BP en contenido de CX. Direccionamiento por Registro Base Cuando el operando esta en memoria en una posición apuntada por el registro BX o BP al que se le añade un determinado desplazamiento Ejemplo: MOV AX, [BP] + 2 Almacena en AX el contenido de la posición de memoria que resulte de sumar 2 al contenido de BP (dentro de segmento de pila). Equivalente a: MOV AX, [BP + 2] Figura 10. Direccionamiento por Registro Base Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/regseg.html. 34 Este tipo de direccionamiento permite acceder, de una forma cómoda, a estructuras de datos que se encuentran en memoria. Direccionamiento Indexado Cuando la dirección del operando es obtenida como la suma de un desplazamiento más un índice (DI, SI). Ejemplo: MOV AX, TABLA [DI] Almacena en AX el contenido de la posición de memoria apuntada por el resultado de sumarle a TABLA el contenido de DI. Figura 11. Direccionamiento indexado. Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/regseg.html. Direccionamiento Indexado Respecto a Una Base Cuando la dirección del operando se obtiene de la suma de un registro base (BP o BX), de un índice (DI, SI) y opcionalmente un desplazamiento. Ejemplo: MOV AX, TABLA [BX] [DI] Almacena en AX el contenido de la posición de memoria apuntada por la suma de TABLA, el contenido de BX y el contenido de DI. 35 2.3.5 Disco Duro En informática, un disco duro o disco rígido (Hard Disk Drive, HDD) es un dispositivo de almacenamiento de datos no volátil que emplea un sistema de grabación magnética para almacenar datos digitales. Se compone de uno o más platos o discos rígidos, unidos por un mismo eje que gira a gran velocidad dentro de una caja metálica sellada. Sobre cada plato, y en cada una de sus caras, se sitúa un cabezal de lectura/escritura que flota sobre una delgada lámina de aire generada por la rotación de los discos. Figura 12. Disco Duro. Autor: Tesista. Fuente: http://www.consejosgratis.es/instalar-un-segundo-disco-duro-en-mi-ordenador/. https://www.hack-urbano.com/como-borrar-por-completo-un-disco-duro/ 2.3.5.1 Estructura Física De Un Disco Duro Figura 13. Estructura Física De Un Disco Duro. Autor: Tesista. Fuente:Imágenes Google. 36 1. Gabinete.- Los discos se encuentran en un gabinete herméticamente sellado, de modo que el aire exterior que contiene una gran cantidad de partículas suspendidas, no penetren al interior de la unidad, a menos que pase por unos filtros especiales que retiran todas las partículas indeseables y permiten el flujo de aire limpio dentro del disco. Si bien, por algún tiempo se manejó que los discos duros venían al vacío, esto no es cierto, ya que, para su funcionamiento es indispensable que se forme un colchón de aire entre la superficie del disco y la cabeza magnética, algo imposible si la unidad estuviera al vacío. 2. Circuitos Electrónicos.- En la parte exterior del gabinete, hay una placa de circuitos electrónicos con varios chips que establecen la comunicación entre la computadora y el interior del disco duro. Esta placa contiene los circuitos de intercambio de datos, los amplificadores que graban los datos en la superficie de los platos y aquellos que recogerán los minúsculos pulsos que captan las cabezas de lectura, amplificándolos y decodificándolos para enviarlos al microprocesador. También incluye los conectores para alimentar el disco duro con +5 y +12 volts (hay discos que trabajan con +5 volts e incluso con menos para máquinas portátiles); en esta placa también se configura la unidad como disco único, master o slave. Aun cuando estos elementos básicos conforman un disco duro, es posible encontrar otros, como un brazo para auto estacionado de cabeza LED's indicadores de actividad del disco, etc., sin embargo, la estructura básica de la unidad es la misma. 3. Actuador.- Es un motor que mueve la estructura que contiene las cabezas de lectura entre el centro y el borde externo de los discos. Un "actuador" usa la fuerza de un electro magneto empujado contra magnetos fijas para mover las cabezas a través del disco. La controladora manda más corriente a través del electro magneto para mover las cabezas cerca del borde del disco. En caso de una pérdida de poder, un resorte mueve la cabeza nuevamente hacia el centro del disco 37 sobre una zona donde no se guardan datos. Dado que todas las cabezas están unidas al mismo “rotor” ellas se mueven al unísono. El desplazamiento de las cabezas de lectura/escritura sobre la superficie de los platos, es necesaria para lograr la recuperación de los datos almacenados en un disco. En discos antiguos, el desplazamiento lo realizaba un motor de pasos conectado al brazo donde iban montadas las cabezas en la actualidad, estos motores han sido sustituidos por una "bobinas de voz" (voice coil), las cuales permiten movimientos más precisos y, lo más importante, pueden autocorregir pequeñas desviaciones que pudiera haber en el proceso de búsqueda de un track de información (además de permitir desplazamientos más veloces. Para su funcionamiento, esta bobina de voz necesita un par de imanes permanentes que producen un campo magnético de cierta intensidad. Sumergida en dicho campo, se encuentra la bobina que está adosada en el brazo de cabezas (puede darse la situación contraria: un imán pegado al brazo y las bobinas rodeándolo) de modo que cuando circula una corriente a través de la bobina, por la atracción y repulsión magnéticas, el brazo de las cabezas tiende a moverse manejando la magnitud de corriente que circule por la bobina, se puede controlar el desplazamiento de las cabezas sobre la superficie del disco. 4. Platos de soporte.- La pieza más importante de todo disco duro son uno o más platos de aluminio, vidrio o cerámica, recubiertos por un fina capa de material ferromagnético de unas cuantas micras de espesor (de entre 3 y 8 micras en los discos modernos. Aquí es donde, finalmente, se almacena la información binaria. 5. Brazos.- En un extremo tiene montadas las cabezas magnéticas y en el otro los elementos necesarios para lograr el desplazamiento de ellas a través de la superficie del disco. 6. Cabezas de grabación y lectura.- Para realizar la lectura y escritura de datos en la superficie de los discos, se necesitan dos cabezas de grabación y lectura, una por cada cara del disco (por supuesto que si hay 38 más de un plato, habrá más cabezas). Las cabezas están unidas por un elemento al que se denomina "actuador". Antes las cabezas eran simples piezas de ferrita (similares a las que se incluyen en cualquier grabadora de casetes casera), pero en la actualidad se fabrican en miniatura, por un método parecido al de los circuitos integrados (cabezas tipo thin film), o se trata de complejos elementos magneto-resistivos que permiten enormes densidades de grabación, redundando en discos cada vez más pequeños y de mayor capacidad. 7. Preamplificadores. 8. Conexión de Alimentación. 9. Bloque de Configuración (Jumper). 10. Puerto de Entrada/Salida. 2.3.5.2 Estructura Física: Cabezas, Cilindros Y Sectores Cada una de las dos superficies magnéticas de cada plato se denomina cara. El número total de caras de un disco duro coincide con el de cabezas. Cada una de estas caras se divide en anillos concéntricos llamados pistas. Finalmente cada pista se divide en sectores. El termino cilindro se utiliza para referirse a la misma pista de todos los discos de una pila. Figura 14. Estructura física de un disco duro. Autor: Tesista. Fuente: http://es.slideshare.net/gematic/tico-disco-duro. 39 2.3.5.3 Direccionamiento De Sectores En Discos Duros La información se organiza en sectores dentro del disco duro. Los discos duros para PC son formateados a bajo nivel por su fabricante con un tamaño de 512 bytes cada uno. La escritura y lectura de sectores en los discos duros se lleva a cabo empleando los servicios BIOS INT 13h y sus extensiones. Los servicios BIOS INT 13h originales especifican la dirección de un sector mediante tres números: Cylinder, Head, Sector (cilindro, cabeza y sector). 2.3.5.3.1 Direccionamiento CHS Al diseñar el PC XT en 1983, los ingenieros de IBM establecieron que los servicios BIOS relativos al manejo de disco duro serían activados por la línea IRQ5 (IRQ6 se destinaba al disquete). Esta línea generaba la interrupción 19 (13h), cuya rutina de servicio disponía de seis servicios estándar: re inicialización, obtención del estado, lectura, escritura, verificación de sectores, y formateo de pistas. Estos servicios ofrecen la posibilidad de leer y escribir en las unidades de disco a nivel de sectores individuales para lo que, además del número de unidad, se requiere pasar a la rutina los valores de geometría correspondientes (Cilindro, Cabeza y Sector concretos) lo que se conoce como direccionamiento CHS ("Cilinder Head Sector"). La especificación de IBM establecía que los siguientes valores para dichos parámetros. Tamaño n del campo (bits) Cilindro 10 Cabeza 8 Sector 6 Valor máximo teórico 2n 1,024 256 64 Rango permitido 0-1,023 0-255 1-63 Total utilizable 1,024 256 63 Tabla 8. Direccionamiento CHS. Autor: Tesista. Fuente: http://www.zator.com/Hardware/H6_2.htm 40 Especificación ATA Aparte de lo anterior, la especificación ATA establecía otras limitaciones para los valores de Cilindro, Cabeza y Sector, eran las siguientes: Tamaño del campo (bits) Cilindro 16 Cabeza 4 Sector 8 Valor máximo teórico 65,536 16 256 Rango permitido 0-65,535 0-15 1-255 Total utilizable 65,536 16 255 Tabla 9. Especificación ATA. Autor: Tesista. Fuente: http://www.zator.com/Hardware/H6_2.htm BIOS estándar con unidad IDE La instalación de una unidad IDE en un PC tradicional (de BIOS estándar) supone que para estar dentro de ambas normas, deberían utilizarse los valores más restrictivos de ambas que serían los siguientes: Cilindros: 1,024 Cabezas: 16 Sectores: 63 Estos números nos conducen a un total máximo de 1024 x 16 x 63 = 1,032,192 clúster, es decir, 528,482,304 bytes (528 MB). Este sería el máximo espacio de disco direccionable mediante los servicios de la interrupción 13h estándar BIOS con una controladora ATA/IDE. 2.3.5.3.2 Direccionamiento CHS Extendida Soportada por un nuevo tipo de BIOS extendidas ("Enhanced BIOS") que aparecieron a partir de 1993/94. 41 En realidad el direccionamiento CHS extendido es un truco aritmético por el que se informa a la BIOS que el disco instalado (suponemos que es una unidad IDE) tiene un número de cilindros, cabezas y sectores distintos de los reales, pero adaptado a lo que puede manejar la BIOS (lo que se denomina geometría trasladada). Para ello, si el número de cilindros del dispositivo IDE es superior a los 1024 soportados por la BIOS, se divide este número por 2, 4, 8 o 16, hasta que el valor resultante sea igual o menor que los mentados 1024. El valor resultante es el que se pasa a la BIOS como número de cilindros. Por su parte, el número de cabezas se multiplica por el factor 2, 4, 8 o 16 utilizado, y éste es el que se suministra a la BIOS (podríamos decir que se cambian cilindros por cabezas). Nota: A pesar del límite teórico de 256, en la práctica ningún disco IDE/ATA ofrece especificaciones con más de 63 sectores lógicos por pista. La razón es que sobrepasar el límite de 63 de la BIOS estándar hubiese complicado aún más las cosas. 2.3.5.3.3 Direccionamiento LBA Como la capacidad de los discos crecía de forma imparable, pronto se hizo necesario sobrepasar también el límite de los 8,455 GB de la interrupción 13h de la BIOS. Para esto se ideó un sistema denominado LBA ("Logical Block Addressing), que implica un sistema radicalmente distinto de direccionar los clúster. En lugar de referirse a ellos en términos geométricos (Cilindro, Cabeza y Sector), a cada clúster se les asigna un número único, Número de Sector. Para ello se numeran 0, 1, 2, ... N-1, donde N es el número total de sectores del disco. Actualmente LBA es el sistema dominante para direccionamiento de discos grandes, puesto que desde que alcanzaron el límite de 8.455 GB, se hizo imposible expresar su geometría en términos de Cilindro, Cabeza y Sector. 42 Observe en realidad LBA es un sistema radicalmente nuevo de direccionamiento que, en principio, no implica por sí mismo ampliar ningún límite. Aunque desde luego, las BIOS que detectan sistemas LBA también disponen de la traducción adecuada para solventar las limitaciones de la combinación BIOS/ATA (saltar la limitación de 528 MB o incluso la de 8.455 GB). Esta traducción es la que resuelve el paso de la barrera, ya que la interrupción 13h no sabe nada sobre direccionamientos LBA. Por supuesto todas las nuevas unidades de disco soportan LBA, y cuando esta circunstancia es auto-detectada por la BIOS, se establece automáticamente este modo de direccionamiento y se habilita la traducción correspondiente. Esta traducción es parecida a la ECHS, aunque el algoritmo es diferente; se denomina traducción auxiliar LBA. La diferencia substancial es que en ECHS, la BIOS traslada los parámetros utilizados por la interrupción 13h desde la geometría trasladada a la geometría local del disco. En la traducción LBA, la BIOS traslada la geometría trasladada directamente en un número de sector. Con posterioridad al establecimiento del sistema, se empezó a utilizar una extensión conocida como LBA48, que aumentaba de 24 a 48 los bits reservados para representar los números de sector. Asumiendo que el formateo se realiza en sectores de 512 Bytes, el método permite unidades con un máximo teórico de 512 x 248 = 144.11 Peta bytes (millones de Gigas). 43 2.3.6 Sistema De Numeración Computacional Y Unidades De Información En informática se usan diversos sistemas de numeración para poder representar datos entre los más principales tenemos. 2.3.6.1 Sistema Binario Es un sistema de numeración que es usado internamente por el hardware de las computadoras actuales. Se basa en la representación de cantidades utilizando los dígitos 1 y 0, por tanto su base es dos (número de dígitos de sistemas). Cada digito de un número representado en este sistema se representa en BIT (contracción de binary digit). Los ordenadores trabajan internamente con dos niveles de voltaje, por lo que su sistema de numeración natural es el sistema binario (encendido '1', apagado '0'). 2.3.6.2 Sistema Octal Es un sistema de numeración cuya base es 8, es decir, utiliza 8 símbolos para la representación de cantidades. Estos sistemas es de los llamados posiciónales y la posición de sus cifras se mide con la relación a la coma decimal que en caso de no aparecer se supone implícitamente a la derecha del número. Estos símbolos son: 0 1 2 3 4 5 6 7. Los números octales pueden construirse a partir de números binarios agrupando cada tres dígitos consecutivos de estos últimos (de derecha a izquierda) y obteniendo su valor decimal. En informática, a veces se utiliza la numeración octal en vez de la hexadecimal. Tiene la ventaja de que no requiere utilizar otros símbolos diferentes de los dígitos. 2.3.6.3 Sistema Decimal Es uno de los sistema denominado posiciónales, utilizando un conjunto de símbolos cuyo significado depende fundamentalmente de su posición relativa al símbolo, denominado coma (,) decimal que en caso de ausencia se supone colocada a la derecha. Utiliza como base el 10, que corresponde al número del símbolo que comprende para la representación de cantidades; estos símbolos son: 0 1 2 3 4 5 6 7 8 9. 44 2.3.6.4 Sistema Hexadecimal Es un sistema posicional de numeración en el que su base es 16, por tanto, utilizara 16 símbolos para la representación de cantidades. Estos símbolos son: 0123456789ABCDEF Su uso actual está muy vinculado a la informática. Esto se debe a que un dígito hexadecimal representa cuatro dígitos binarios (4 bits = 1 nibble); por tanto, dos dígitos hexadecimales representan ocho dígitos binarios (8 bits = 1 byte, (que como es sabido es la unidad básica de almacenamiento de información). Dado que nuestro sistema usual de numeración es de base decimal, y por ello sólo disponemos de diez dígitos, se adoptó la convención de usar las seis primeras letras del alfabeto latino para suplir los dígitos que nos faltan: A = 10, B = 11, C = 12, D = 13, E = 14 y F = 15. Como en cualquier sistema de numeración posicional, el valor numérico de cada dígito es alterado dependiendo de su posición en la cadena de dígitos, quedando multiplicado por una cierta potencia de la base del sistema, que en este caso es 16. 2.3.6.5 Unidades De Información En los sistemas actuales es habitual medir la información en gigabytes, aproximadamente mil millones de bytes, pero existen otras unidades intermedias también muy empleadas, como el Kbyte o kilobyte y el megabyte. Al hablar de procesadores es habitual medir su capacidad de direccionamiento en bits, al igual que la de los registros internos con que cuenta. Así, la mayoría de los procesadores actuales, entre los que se cuentan los compatibles x86 o los PowerPC de los Mac, son procesadores de 32/64 bits, ya que ése es el direccionamiento máximo para el que tienen capacidad. 45 Los procesadores tienen su unidad de información por el tamaño de los registros internos y el bus de datos. Así en el microprocesador 8086 que tiene registros internos de 16 bits su palabra es de 16 bits, en el caso del 80386 que tiene registros internos de 32 bits su palabra es de 32 bits. Como todos los procesadores en la actualidad compatibles x86, heredan la arquitectura del 8086 se puede definir la tabla de unidad de información. Byte Nombre Nemónico Tamaño(bits) BYTE 8 Palabra WORD 16 Doble Palabra DWORD 32 Cuádruple Palabra QWORD 64 Tabla 10. Unidades de Información Microprocesador. Autor: Tesista. Fuente:Conocimientos adquiridos del tesista. 2.3.7 BIOS La BIOS es un un circuito integrado, que acompaña al resto de los elementos que existen en la placa principal del ordenador. Se aloja en una memoria tipo EPROM. Básicamente se trata de un programa que toma el control cuando el ordenador se pone en marcha, llevando a cabo todo el proceso de comprobación y detección de memoria y dispositivos, configurando un área de memoria con datos de control de los dispositivos y, finalmente, transfiriendo el control al programa de arranque que corresponda, normalmente alojado en un disco duro, disquete o CD-ROM. Durante ese proceso de inicio, la BIOS configura en la memoria una serie de vectores de interrupción. Éstos facilitan el acceso a los servicios que ofrece la propia BIOS, servicios que evitan que tengamos que comunicarnos directamente con cada dispositivo y, por tanto, tengamos que conocer todos los detalles sobre su funcionamiento. 46 La gestión de interrupciones en modo protegido es diferente al empleado en modo real, por lo que desde sistemas que usan el modo protegido, todos los de 32 bits que funcionan sobre procesadores Pentium, Core o compatibles, no es posible el acceso directo a la BIOS. Existen, no obstante, alternativas a los servicios de la BIOS y caminos alternativos para llegar a ella. 2.3.7.1 El área de parámetros de la BIOS Como se describió anteriormente, la BIOS es un programa que se encarga de la puesta en marcha o iniciación del ordenador, aparte de ofrecer servicios de bajo nivel tanto al sistema operativo como a las aplicaciones. Este programa, alojado en memoria que sólo puede ser leída, necesita un área de lectura/escritura para almacenar parámetros que no son constantes, como el tamaño de la memoria instalada en el sistema, el número de unidades de disco, el estado actual del teclado, etc. Para todos estos datos se reserva un área de memoria RAM, conocida como área de parámetros de la BIOS, que está justo detrás de la tabla de vectores de interrupción, siendo su tamaño variable según la BIOS específica de que se trate. La dirección de inicio de esta área de parámetros es, por lo general es, 0:1024 o, 40h: 0h, que es equivalente a la anterior. El segmento se expresa en párrafos (16 bytes), que 1024 dividido entre 16 es 64 y que 64 en hexadecimal es 40h. Asumiendo que utilizamos 40h como segmento, la dirección de cada variable existente en el área de parámetros de la BIOS tendrá como referencia el desplazamiento 0. En la siguiente tabla se enumera la dirección, tamaño y contenido de algunos elementos del área de parámetros de la BIOS. Esta configuración se remonta a los tiempos de la aparición del PC por lo que, en la actualidad, puede no contener una información completamente exacta. 47 Offset 00h- 06h 08h- 0Eh 10h Tamaño Descripción WORD Dirección E/S base del primer-cuarto puerto serie (0 si no instalado) WORD Dirección E/S base del primer-tercer puerto paralelo (0 si no instalado) WORD Hardware instalado: bits 15-14: número de puertos paralelos bit 13: [PC Convertible] = 1 si hay modem interno bit 12: reservado bits 11- 9: número de puertos serie bit 8: reservado bits 7- 6: número de disqueteras - 1 bits 5- 4: modo de vídeo inicial bit 3: reservado bit 2: [máquinas PS] = 1 si hay dispositivo apuntador [máquinas no PS] reservado bit 1: = 1 si hay coprocesador bit 0: = 1 si hay disquete disponible para arrancar Tabla 11. Área De Parámetros De La BIOS. Autor: Tesista. Fuente: http://es.wikipedia.org/wiki/Llamada_de_interrupci%C3%B3n_del_BIOS A más de los datos anteriores podemos los siguientes: Datos de configuración del hardware: Contiene las direcciones de hasta 4 puertos seriales y 4 puertos paralelos, información del hardware y cantidad de memoria RAM instalados, y cierta información del estado de inicialización. Datos del Teclado: Contiene el buffer del teclado (16 caracteres), el estado de varias teclas como ambas teclas de CTRL y ALT, las teclas INS, NumLook, CapsLook, etc., y un byte para almacenar el carácter generado con un código de 3 dígitos usando ALT + teclado numérico. Datos del Disquete: Contiene el estado de la disquetera y de su controlador. Datos del Video: Contenía información de estado de la tarjeta de video activa. Datos del Casete: Contiene información de estado de la unidad de casete. Datos del Timer: Contenía un contador de Tics, (que ocurría 18,2 veces por segundo), desde que el computador se encendía. Servía para determinar cuál era la hora del día. 48 2.3.7.2 Vectores de Interrupción En informática el vector de interrupciones es un vector que contiene el valor que apunta a la dirección en memoria del gestor de una interrupción. En los procesadores Intel de la línea X86, hay dos tipos de interrupciones: por hardware y por software. El método para realizar la interfaz con el BIOS es el de las interrupciones de software. A continuación se listan algunas interrupciones del BIOS. INT 00H: División entre cero. Llamada por un intento de dividir entre cero. Muestra un mensaje y por lo regular se cae el sistema. INT 01H: Un solo pasó. Usado por DEBUG y otros depuradores para permitir avanzar por paso a través de la ejecución de un programa. INT 02H: Interrupción no enmascarare. Usada para condiciones graves de hardware, tal como errores de paridad, que siempre están habilitados. Por lo tanto un programa que emite una instrucción CLI (limpiar interrupciones) no afecta estas condiciones. INT 03H: Punto de ruptura. Usado por depuración de programas para detener la ejecución. INT 04H: Desbordamiento. Puede ser causado por una operación aritmética, aunque por lo regular no realiza acción alguna. INT 05H: Imprime pantalla. Hace que el contenido de la pantalla se imprima. Emita la INT 05H para activar la interrupción internamente, y presione las teclas Cltr + PrtSC para activarla externamente. La operación permite interrupciones y guarda la posición del cursor. INT 08H: Sistema del cronometro. Una interrupción de hardware que actualiza la hora del sistema y (si es necesario) la fecha. Un chip temporizador programable genera una interrupción cada 54.9254 milisegundos, casi 18.2 veces por segundo. 49 INT 09H: Interrupción del teclado. Provocada por presionar o soltar una tecla en el teclado. INT OBH, INT OCH: Control de dispositivo serial. Controla los puertos COM1 y COM2, respectivamente. INT 0DH, INT OFH: Control de dispositivo paralelo. Controla los puertos LPT1 y LPT2, respectivamente. INT 0EH: Control de disco flexible. Señala actividad de disco flexible, como la terminación de una operación de E/S. INT 10H: Despliegue en vídeo. Acepta el número de funciones en el AH para el modo de pantalla, colocación del cursor, recorrido y despliegue. INT 11H: Determinación del equipo. Determina los dispositivos opcionales en el sistema y regresa el valor en la localidad 40:10H del BIOS al AX. (A la hora de encender el equipo, el sistema ejecuta esta operación y almacena el AX en la localidad 40:10H). INT 12H: Determinación del tamaño de la memoria. En el AX, regresa el tamaño de la memoria de la tarjeta del sistema, en términos de kilobytes contiguos. INT 13H: Entrada/salida de disco. Acepta varias funciones en el AH para el estado del disco, sectores leídos, sectores escritos, verificación, formato y obtener diagnóstico. 2.3.7.3 Servicios De La BIOS La BIOS ofrece servicios para manipular la pantalla, acceder a los discos, enviar datos a la impresora, leer el teclado o comunicarnos mediante los puertos serie. Con el uso de los vectores de interrupción. 50 2.3.8 Lenguaje Ensamblador El lenguaje ensamblador trabaja con nemónicos, que son grupos de caracteres alfanuméricos que simbolizan las órdenes o tareas a realizar. El lenguaje ensamblador expresa las instrucciones de una forma más natural al hombre a la vez que es muy cercana al microprocesador, ya que cada una de esas instrucciones se corresponde con otra en código máquina. La traducción de los nemónicos a código máquina entendible por el microprocesador la lleva a cabo un programa ensamblador. El programa escrito en lenguaje ensamblador se denomina código fuente. El programa ensamblador proporciona a partir de este fichero el correspondiente código máquina. Código Fuente Está compuesto por una sucesión de líneas de texto. Cada línea puede estructurarse en hasta cuatro campos o columnas separadas por uno o más espacios o tabulaciones entre sí. Campo de etiquetas.- Expresiones alfanuméricas escogidas por el usuario para identificar una determinada línea. Todas las etiquetas tienen asignado el valor de la posición de memoria en la que se encuentra el código al que acompañan. Campo de código.- Corresponde al nemónico de una instrucción, de una directiva o de una llamada a macro. Campo de operandos y datos.- Sonoperandos que precisa el nemónico utilizado. Según el código, puede haber dos, uno o ningún operando. Campo de comentarios.- Dentro de una línea, todo lo que se encuentre a continuación de (;) o dentro de /**/ será ignorado por el programa ensamblador y considerado como comentario. Al programar en ensamblador no sólo se utiliza el conjunto de instrucciones y registros de un cierto microprocesador sino que, además, se usarán dichas instrucciones para acceder a elementos hardware, como el adaptador de vídeo, el teclado o los buses de comunicaciones de una cierta arquitectura de ordenador. De igual manera, para efectuar ciertas tareas se utilizarán servicios puestos a disposición de las aplicaciones por el sistema operativo. 51 2.3.9 Lenguaje C C es un lenguaje de programación creado en 1972 por Dennis M. Ritchie en los Laboratorios Bell como evolución del anterior lenguaje B. Es un lenguaje orientado a la implementación de Sistemas Operativos, concretamente Unix. C es apreciado por la eficiencia del código que produce y es el lenguaje de programación más popular para crear software de sistemas, aunque también se utiliza para crear aplicaciones. “Se trata de un lenguaje de tipos de datos estáticos, débilmente tipificado, de medio nivel pero con muchas características de bajo nivel. Dispone de las estructuras típicas de los lenguajes de alto nivel pero, a su vez, dispone de construcciones del lenguaje que permiten un control a muy bajo nivel. Los compiladores suelen ofrecer extensiones al lenguaje que posibilitan mezclar código en ensamblador con código C o acceder directamente a memoria o dispositivos periféricos.” (Fuente: http://es.wikipedia.org/wiki/C_%28lenguaje_de_programaci%C3%B3n%29) Propiedades Un núcleo del lenguaje simple, con funcionalidades añadidas importantes, como funciones matemáticas y de manejo de archivos, proporcionadas por bibliotecas. Un sistema de tipos que impide operaciones sin sentido. Declaración en C Char Short Int Unsigned long int unsigned long char * Float Doublé long doublé Tipo de datos byte palabra doble palabra doble palabra doble palabra doble palabra doble palabra precisión simple precisión doble precisión extendida Sufijo de gas b w l l l l l s l t Tamaño (en bytes) 1 2 4 4 4 4 4 4 8 12 Tabla 12. Tipos de Datos de Programación C. Autor: Tesista. Fuente: Conocimientos adquiridos tesista. 52 2.3.10 Herramientas de programación Para poder programar en ensamblador se precisa de algunas herramientas básicas, como un editor para introducir el código, un ensamblador para traducir el código a lenguaje de maquina y un enlazador para crear archivos binarios puros enlazar librerías del sistema según sea necesario etc.. Aparte también se necesitan módulos con declaraciones de macros, estructuras de datos y funciones, utilidades para generar archivos de recursos, etc. Todo ello, lógicamente, para el sistema operativo concreto sobre el que se pretende programar. 2.3.10.1 Editores Editor de textos son aplicaciones que permiten introducir el código, guardarlo en un archivo, recuperarlo y, en general, efectuar todas las tareas habituales de edición. Se puede usar virtualmente cualquier editor de texto sin formato, desde el EDIT de DOS, el Bloc de notas de Windows o vi de Unix hasta los editores integrados en entornos de desarrollo como Visual Studio, Eclipse y similares. Existen editores específicos, que se podrían denominar entornos integrados de desarrollo o IDE, que ahorran trabajo al contar con opciones para efectuar el ensamblado, enlace, incluso, la ejecución sin necesidad de abandonar la edición de código. Entre los más conocidos editores con interfaz de desarrollo tenemos: Assembler Editor: Editor, compilador y enlazador de programas escritos en lenguaje ensamblador compatible con TASM, MASM. Se pude instalar en plataformas de Microsoft. 53 Figura 15. Editor Assembler Editor. Autor: Tesista. Fuente: Captura de pantalla. Nasm-IDE: Editor, compilador y enlazador, es compatible solo con nasm y Windows DOS. NasmEdit: Igual que Nasm-IDE pero es compatible con cualquier plataforma que pueda ejecutar java 2. Figura 16. Editor Nasm-IDE. Autor: Tesista. Fuente: Captura de pantalla. 54 2.3.10.2 Ensambladores Un ensamblador es como un compilador de cualquier lenguaje, el ensamblador toma un archivo de texto con código fuente como entrada y, en respuesta, genera un nuevo archivo con esas mismas sentencias pero en lenguaje de un determinado procesador. Los más conocidos ensambladores para x86 son los siguientes: Masm: Es el ensamblador más usado en DOS y Windows, está desarrollado por la misma empresa que creó dichos sistemas Microsoft. Es bastante potente y puede utilizarse para crear programas DOS y Windows, así como bibliotecas y controladores de dispositivos. Como los demás ensambladores, MASM se invoca desde la línea de comandos directamente o, en caso de contar con él, desde un editor previa configuración. Nasm: Net Wide Assembler, es un ensamblador bajo licencia BSD para plataformas Intel x86, permite escribir programas en 16, 32, 64 bits. Es compatible para múltiples plataformas, entre ellas DOS, Windows y Linux. Esto conlleva una gran ventaja, ya que podemos usar exactamente la misma herramienta en todos los sistemas, sin tener que cambiar de sintaxis, parámetros, etc. Nasm puede generar como salida varios formatos binarios. Gas (GNU Assembler): Principal ensamblador en plataformas Linux, tiene licencia de software libre, es compatible con la sintaxis de AT&T, permite generar como salida varios formatos binarios. Otros Ensambladores: Existen otros ensambladores como TASM (Turbo Assembler), A86 etc. 55 2.3.10.3 Enlazadores Los ensambladores son traductores que toman el código fuente y, partiendo de cada sentencia, generan una secuencia de bytes, por regla general muy corta, que es el código objeto. El conjunto de todas las secuencias de bytes, una por instrucción, se almacenan en un archivo que no es directamente ejecutable. Dicho archivo contiene una versión de nuestro programa en el lenguaje de la máquina, pero no cuenta con la información adicional necesaria para que el sistema operativo o el procesador sepa gestionarlo. El enlazador es La herramienta encargada de tomar el código objeto generado por el ensamblador, añadir los encabezados apropiados y producir un nuevo archivo ya ejecutable esto es el conocido como linker o enlazador. En el caso para generar gestores de arranque el enlazador produce código puramente binario sin bibliotecas que dependan del sistema operativo en tiempo de ejecución. Por regla general, cada ensamblador cuenta con su propio enlazador. Si utiliza MASM el enlazador será LINK. Para TASM el correspondiente enlazador es TLINK. NASM no se acompaña de un enlazador propio, aunque puede utilizarse cualquiera de distribución libre como es ALINK o bien, en el caso de Linux, usar el propio del sistema LINK. 56 2.3.10.4 GCC GNU C Compiler fue iniciado en 1984 para crear un sistema operativo basado en software libre similar a UNIX y, así promover la libertad y la cooperación entre usuarios de ordenadores y programadores. GCC es un compilador rápido, muy flexible, y riguroso con el estándar de C ANSI. Como ejemplo de sus múltiples virtudes, se tiene que gcc puede funcionar como compilador cruzado para un gran número de arquitecturas distintas. Gcc no proporciona un entorno IDEs, es solo una herramienta más a utilizar en el proceso. Gcc se encarga de realizar (o encargar el trabajo a otras utilidades) el pre procesado del código, la compilación, y el enlazado. Dicho de otra manera, se proporciona a gcc código fuente en C, y él nos devuelve un archivo binario compilado para nuestra arquitectura. Gcc no genera código binario alguno, sino código ensamblado. La fase de ensamblado a código binario la realiza el ensamblador de GNU (gas), y el enlazado de los objetos resultantes, el enlazador de GNU (ld). Este proceso es transparente para el usuario, ya que a no ser que se lo especifiquemos, gcc realiza el paso desde código en C a un binario ejecutable automáticamente. A través del tiempo GCC ha sido extendido para dar soporte a muchos lenguajes adicionales, incluyendo Fortran, ADA, Java y Objective-C, C, C++. A continuación se describen las etapas correspondientes al conjunto de herramientas de compilación gcc que permite traducir programas escritos en el lenguaje de programación C. Figura 17. Etapas de gcc. Autor: Amelia Ferreira © 2008. Fuente: http://learnassembler.com/entorno.html. 57 2.4 Investigación Experimental En la realización del proyecto de fin de carrera, para la investigación experimental se analiza como las variables independientes de la investigación afectan al aprendizaje y desarrollo de nuevos gestores de arranque y sistemas operativos, que en este caso es la falta de información del código por parte del software propietario y la escasa documentación técnica por parte del software libre. Razón por la cual se desarrolla documentación técnica del código del gestor de arranque grub, su funcionamiento, como modificarlo y reconstruirlo. Con los conocimientos obtenidos se procederá a crear un prototipo de gestor de arranque. Dando a la comunidad más documentación para que se pueda profundizar en el tema y aportar nuevas ideas, corregir errores etc. 2.5 Plan de Recolección de Información Una vez planteada la investigación y realizada todos los estudios sobre las herramientas necesarias en la administración de los gestores de arranque se efectúa la recolección de información con el fin de dar respuesta al problema planteado como propuesta de tesis. Las técnicas que se utilizó para recolectar información son: Lectura del funcionamientos de los gestores de arranque propietarios en este caso Windows. Técnicas de Ingeniería inversa aplicadas a los gestores de arranque propietarios. Lectura del funcionamiento de los gestores de arranque de código libre en este caso LILO y GRUB Legacy. Técnicas de ingeniería inversa aplicada a los gestores de arranque de código libre, si bien se tiene acceso al código se debió probar su funcionamiento práctico. Métodos de depuración de código tanto para los gestores de arranque propietarios como de software libre. 58 2.6 Plan de Procesamiento de Información Con la información recopilada se procedecio a determinar cuál gestor de arranque permite profundizar su estudio dando como resultado el gestor de arranque GRUB LEGACY por los siguientes motivos: Grub Legacy tiene varios años funcionando lo que ha permitido profundizar en el estudio del código. El código de GRUB Legacy es más pequeño que los gestores de la actualidad lo que permite seguir el funcionamiento del código. Grub Legacy es de software libre con licencia GNU GPL lo que permite modificar su código, reconstruir el ejecutable y poner el código modificado y su ejecutable a disposición de la comunidad para libre uso. GRUB LEGACY permite una mejor fuente de información si bien ya no tiene desarrollo permite obtener una visión clara del funcionamiento del gestor de arranque ya que su código fue evolucionando y se tiene acceso a sus distintas versiones. 2.7 Modelo de Desarrollo El modelo a utilizarse para el desarrollo del proyecto fue un modelo de prototipo que es un modelo a escala o facsímil de lo real, pero no tan funcional para que equivalga a un producto final, ya que no lleva a cabo la totalidad de las funciones necesarias del software final. Proporcionando una retroalimentación temprana por parte de los usuarios acerca de la aplicación del software. El objetivo de utilizar el modelo de desarrollo de prototipo es centrarse en una representación de los aspectos del software que sean visibles para el usuario final que en este caso será la configuración de la interfaz con el usuario y la documentación técnica de cómo se codifico el software. Con un modelo de prototipo no vamos a centrar en los aspectos básicos del gestor de arranque para dar un entendimiento global de su funcionamiento. 59 FASES MÉTODO DE PROTOTIPOS Estas fases se implementaran en el diseño de la solución en el capitulo 3. Lo siguiente que se presenta es un resumen de lo que se realizará en cada fase teniendo en cuenta el modelo de desarrollo de prototipos.. Investigación preliminar Se determinará el problema y su ámbito, la importancia y los efectos potenciales que tendrán sobre la organización, identificar una idea general de la solución para realizar un estudio de factibilidad que determine la factibilidad de una solución software. Definición de los requerimientos del sistema Esta es la fase más importante de todo el ciclo de vida del método de prototipos, el objetivo en esta fase es determinar todos los requerimientos y deseos que el proyecto que está deseando implementar. Esta etapa es un proceso que busca aproximar las visiones del usuario y del desarrollador mediante sucesivas iteraciones. Diseño y construcción Lo que se consigue en esta fase en obtener un prototipo inicial, aquí el desarrollador debe concentrarse en construir un sistema con la máxima funcionalidad. Evaluación Se modifica y se evalúa cuantas veces sea necesario hasta que se tenga claro conocimiento del funcionamiento del gestor de arranque y se genera documentación técnica. 60 Diseño técnico En esta etapa el sistema debe ser rediseñado y tener la respectiva documentación guiándose en los estándares que tiene la organización la cual servirá como ayuda en mantenciones futuras del mismo. En este punto existen dos etapas: Producción de una documentación de diseño la cual específica y describe la estructura del software, interfaces de usuario, funciones y el control de flujo. Producción de todo lo requerido para promover cualquier mantención futura del software. Programación y prueba En esta etapa es donde los cambios identificados en el diseño técnico son implementados y probados para asegurar la corrección y completitud de los mismos con respecto a los requerimientos. Las pruebas serán de realizarse tantas veces sea necesarias para verificar cualquier tipo de anomalía en el sistema. Operación y mantención En esta fase se realiza ya la instalación y mantención del software. Si existiese el caso en el cual se requiera una manutención entonces el proceso de prototipo es repetido y se definirá un nuevo conjunto de requerimientos. 61 CAPITULO 3 3 DISEÑO DE LA SOLUCIÓN 3.1 Antecedentes Para la creación, modificación y estudio de los gestores de arranque no existen herramientas de cuarta generación, solo se tiene a disposición enlazadores ensambladores, preprocesadores, por lo tanto para el diseño de la solución se procedió a revisar la teoría del funcionamiento de los gestores de arranque y con las herramientas antes mencionadas en el capítulo 2, se procedió a realizar pruebas iterativas con modificaciones del código, aplicación de técnicas de ingeniería inversa etc. Logrando generar la siguiente documentación, como caso de uso se modificara el gestor de arranque GRUB LEGACY. 3.2 Gestor de Arranque Los gestores de arranque contienen el primer programa que la computadora carga al iniciar su funcionamiento. La computadora al encender realiza un proceso denominado POST (Power On Self Test auto prueba de encendido) este proceso se encuentra quemado en la memoria ROM de la pc, es un proceso de verificación e inicialización de los componentes de entrada y salida en un sistema de cómputo que se encarga de configurar y diagnosticar el estado del hardware, una vez que termina su verificación carga a memoria desde un dispositivo arrancable código de 512 bytes de tamaño y procede a darle el control de la pc. Encendido PC Post(Power On Selft) Cargar y ejecutar programa arrancable. Figura 18. Flujo General de Inicio de la Pc. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 62 Para seleccionar un dispositivo arrancable la pc busca dentro de los dispositivos configurados coma de arranque y selecciona el primero que cumpla como dispositivo arrancable como lo muestra la siguiente figura. Figura 19. Flujo de Selección y Carga de Código de Arranque. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 3.2.1 Codificación y Funcionamientos de los Gestores de Arranque El funcionamiento del gestor de arranque se lo dividirá en tres etapas Primera Etapa Tamaño en Bytes Segunda Etapa 512 Tercera Etapa variable variable Cargar a memoria y Cargar a memoria Cargar a memoria y Función ejecutar segunda y ejecutar tercera ejecutar Sistema etapa etapa Operativo Tabla 13. Etapas del Gestor de Arranque. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 63 Primera Etapa El código de la primera etapa debe tener un tamaño de exactamente 512 bytes. Su último número hexadecimal deber ser 0x55AA, que es el número. La primera etapa debe ser inyectada en el sector de arranque de los dispositivos de almacenamiento. Con esta inyección de código el dispositivo de almacenamiento se convierte en un dispositivo de arranque. La primera etapa es generalmente es escrita solo en leguaje ensamblador pero como ya se vio anteriormente en el proceso de compilación de gcc todo programa escrito en lenguaje de alto nivel tiene que pasar por una etapa de ensamblaje. El motivo de escribir su código en lenguaje ensamblador es que al momento de enlazarle para producir el código binario puro este debe medir exactamente 512 bytes y sus últimos números hexadecimales deben ser 0x55AA. En lenguaje ensamblador podemos delimitar el tamaño de nuestro archivo binario puro. El código de la primera etapa del gestor de arranque o la primera etapa del gestor de arranque es denominado MBR Master Boot Record. 3.3 MBR El MBR (master boot record) es conocido como registro de arranque principal, o como registro de arranque maestro, el MBR debe estar almacenado en el primer sector ("sector cero") de un dispositivo de almacenamiento de datos, como un disco duro. El funcionamiento del MBR difiere en los casos de los gestores de código propietario como de código libre. En el caso de Microsoft se realizó el estudio del gestor de arranque NTLDR, en el caso de GNU Linux se realizó un estudio del gestor de arranque GRUB 64 3.4. NTLDR NTLDR (New Technology Loader) es el gestor de arranque de las plataformas de Windows en sus distintas versiones hasta Windows XP. 3.4.1 Estudio NTLDR Se realizó un estudio sobre el NTLDR que inicia el Sistema Operativo XP de 32 bits Servipack 2. Debido a que el MBR debe encontrarse en el sector cero o sector de arranque del disco duro se procede a examinar los 512 bytes del sector que en la especificación CHS vendría ser Cilindro cero, Cabecera cero, sector 1. Ejecutamos la herramienta de software libre HexEdit instalado sobre el Sistema Operativo XP como administrador y abrimos el código hexadecimal almacenado en el disco duro. Figura 20. Sector Cero Disco Duro con Windows XP. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 65 El código de 512 bytes de tamaño del gestor de arranque NTLDR se divide en la sección de código, sección de errores, sección definida por Windows, sección de tabla de particiones, sección de firma. Dirección 0x0000 0x013C 0x01B4 0x01BC 0x01BE 0x01FE Descripción Sección código Sección de errores Sección definida por Windows 2 bytes; normalmente 0x0000 Tabla de particiones del disco duro. Firma del MBR (0x55AA) Tabla 14. Almacenamiento del Master Boot Record de NTLDR. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 3.4.1 .1 Sección de Código La sección de código corresponde a los primeros 300 bytes como se muestra en la siguiente figura. Figura 21. Sección de código de NTLDR. Autor: Tesista. Fuente: Desarrollo de tema de tesis. El estudio de la sección de código se lo dejara para su revisión más adelante en el tema Desensamblaje de la Sección de Código debido a que se debe tener información de los demás secciones del MBR del gestor de arranque NTLDR. 66 3.4.1 .2. Sección de Mensaje de Errores El objetivo de la sección de mensajes de errores es presentar en pantalla al usuario de la pc que no se pudo encontrar una partición valida en el disco duro que se pueda continuar su ejecución. Nota: Se detalla que es una partición valida en la sección de tabla de particiones. Figura 22. Sección de Mensaje de Errores. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Como se observa en la figura anterior la sección de Errores del gestor de arranque NTLDR tiene almacenado el mensaje Tabla de partición no valida. Error al cargar el sistema operativo. Falta el sistema operativo en código ascci. 3.4.1 .3 Sección definida por Windows Las secciones definidas por Windows son dos: En la primera sección definida por Windows en el NTLDR va desde el byte 0x01B5 al byte 0x01B7, tres bytes, lo que representan es la longitud en bytes del mensaje de error esto difiere a causa de los distintos idiomas en que se instala el gestor de arranque. Figura 23. Sección definida por Windows parte 1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 67 En la segunda sección definida por Windows en el NTLDR va desde el byte 0x01B8 la byte 0x01BB, lo que representan es la firma del disco duro, el sistema operativo utiliza estos bytes para determinar la información del disco. Figura 24. Sección definida por Windows parte 2. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En el gestor de arranque del NTLDR podemos observar que la primera parte indica que la longitud del mensaje de error es de 0x6E o 111 caracteres. En la segunda parte es la firma del disco que es usada por el registro de Windows este código es muy importante para el manejo del sistema operativo. 3.4.1 .4 Sección Tabla de Particiones Figura 25. NTLDR Sección Tabla de Particiones. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La tabla de particiones en el NTLDR consta de 64 bytes, comenzando en el byte 0x01BE hasta el byte 0x01FD, los 64 bytes comprenden 4 registros de particiones de 16 bytes denominadas primarias o 3 registros de particiones primarias y 1 registro de una partición extendida. Se revisara teoría sobre la tabla de particiones para proceder al verificar como está constituida la sección de tabla de particiones en el gestor de arranque NTLDR en la sección Estudio de la tabla de particiones del gestor de arranque NTLDR. Partición de Disco 68 Una partición de un disco duro o unidad flash es una división lógica de una unidad física para poder organizar el almacenamiento, en la cual se alojan y organizan los archivos mediante un sistema de archivos. Un disco duro puede dividirse en varias particiones. Cada partición funciona como si fuera un disco duro independiente. El propósito a conseguir es que se pueda utilizar un solo disco físico, como varios discos lógicos independientes. Al instalar dos sistemas operativos sobre un mismo disco duro no sería factible realizarlo sin la técnica de la partición, se necesitarían dos discos físicos, con la técnica de la partición se pueden instalar n sistemas operativos sobre un disco duro al menos hasta que la capacidad de almacenamiento del disco duro lo permita. Creando una partición para cada sistema operativo que se desea instalar. Los disquetes generalmente no se particionan. No hay ninguna razón técnica para ello, pero dado que son tan pequeños, particionarlos sería útil sólo en extrañas ocasiones. Los CD-ROM tampoco se suelen particionar, ya que es más fácil utilizarlos como un disco grande, y raramente existe la necesidad de tener varios sistemas operativos en uno de ellos. En el registro de la tabla de particiones se indica que partición se encuentra activa cual es el tamaño de dicha partición. Solo una partición puede estar activa. La siguiente figura muestra un ejemplo de cómo está estructurado registro de tabla de particiones en el MBR. Tabla de Partición 64 bytes Partición Tamaño Registro Partición 1 16 BYTES Registro Partición 2 16 BYTES Registro Partición 3 16 BYTES Registro Partición 4 16 BYTES Tabla 15. Estructura de la tabla de particiones. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 69 El PC al cargar el MBR el cual contiene el registro de la tabla de particiones buscara la partición primaria o lógica que contiene el sistema operativo, una vez que la encuentra procede a cargar el sistema operativo desde dicha partición. Estructura De Un Registro De Partición Un registro de de partición tiene un tamaño de 16 bytes los cuales se estructuran en el siguiente orden: 1 Byte: Marca de arranque si el bit 7 está activo es una partición de arranque, los otros bits deben ser ceros. 3 Bytes: Indica la especificación CHS (Cilindro, cabecera, sector) de inicio. 1 Byte: Tipo de sistema de archivo de la partición. Ejemplo: 00 Sin sistema de archivo, 01 Fat12 etc. 3 Bytes: Indica la especificación CHS (Cilindro, cabecera, sector) final. 4 Bytes: Indica la especificación LBA(Logical Block Addressing) 4 Bytes: Tamaño de la partición que está definiendo en sectores Tipos De Particiones Existen tres tipos de de particiones: Partición Primaria: Son las divisiones primarias del disco, solo puede haber 4 de éstas o 3 primarias y una extendida. Depende del registro de tabla de particiones. Un disco físico completamente formateado consiste, en realidad, de una partición primaria que ocupa todo el espacio del disco y posee un sistema de archivos. A este tipo de particiones, prácticamente cualquier sistema operativo puede detectarlas y asignarles una unidad, siempre y cuando el sistema operativo reconozca su formato (sistema de archivos). 70 Partición Extendida: También conocida como partición secundaria es otro tipo de partición que actúa dentro de una partición primaria, sirve para contener múltiples unidades lógicas en su interior. Su objetivo principal es romper la limitación de 4 particiones primarias en un solo disco físico. Solo puede existir una partición de este tipo por disco, y solo sirve para contener particiones lógicas. Por lo tanto, es el único tipo de partición que no soporta un sistema de archivos directamente. Partición Lógica: Ocupa una porción de la partición extendida o la totalidad de la misma, la cual se ha formateado con un tipo específico de sistema de archivos (FAT32, NTFS, ext2,...) y se le ha asignado una unidad, así el sistema operativo reconoce las particiones lógicas o su sistema de archivos. Puede haber un máximo de 23 particiones lógicas en una partición extendida. Linux impone un máximo de 15, incluyendo las 4 primarias, en discos SCSI y en discos IDE 8963. Figura 26. NTLDR Tipo de Particiones. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Estudio de la Tabla de Particiones del Gestor de Arranque NTLDR La estructura del registro de la tabla de particiones del gestor de arranque NTLDR es el siguiente. Figura 27. Tabla de Particiones Hexadecimal. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 71 Partición 1 1 Byte: 80 en binario 1000 000: Lo cual indica el bit 7 está activo es decir la primera partición es la partición activa o de arranque. 3 Bytes: 01 01 00: Indica que la primera partición inicia en el cilindro 0 cabecera 1 sector 1. 1 Byte: 07: Indica que la partición esta formateada con el sistema de archivos NTFS 3 Bytes: FE FF FF: Indica que la partición finaliza en el cilindro 1024, cabecera 16 sector 63. 4 Bytes: 3F 00 00 00: Indica que la partición iniciara en el sector 3F o 63 en decimal en caso de soportar LBA 4 Bytes: B2 8C 7F 02: Indica que el el tamaño de la partición es 02 7F 8C B2 o en decimal 41913522 sectores suponiendo que cada sector es de 512 bytes el tamaño es de 20 GB. Partición 2, 3, 4 Las particiones están inactivas y no están formateadas con ningún sistema de archivo. 3.4.1 .5. Sección de Firma La firma es un estándar para indicarle a la pc que es un master boot record. Todo MBR debe terminar con el código en hexadecimal 55 AA los dos últimos bytes de código de 512 bytes. Figura 28. NTLDR Firma. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Como se observa en la figura el gestor de arranque NTLDR termina con la firma 55 AA que indica que es un MBR. 72 3.4.2. Des ensamblaje de la Sección de Código Existen diversas maneras para desensamblar el código en hexadecimal como por ejemplo copiar el código a un archivo utilizando una herramienta en código libre como gcc y proceder a desensamblar dicho archivo igualmente utilizando una herramienta de software libre como por ejemplo objdump. En este caso se utilizara como herramienta la página web http://www2.onlinedisassembler.com/odaweb/, en esta página se escogen como parámetros los siguientes: Arquitectura=i8086: Debido a que al iniciar el funcionamiento del pc esta se encuentra en modo real y el modo real emula un microprocesador 8086. Base Address=0x7C00: Por el motivo que este código será cargado a memoria en la dirección 0x7C00. Y se procede a desensamblar dividiéndole en partes para su mejor comprensión. Adicional se ha comentado técnicamente el código. 3.4.2. 1. Primera Parte Del Código Memoria 0x7C00 0x7C02 0x7C04 0x7C07 0x7C08 Hexadecimal 33c0 8ed0 bc007c fb 50 Instrucción Ensamblador(GAS) xor %ax,%ax mov %ax,%ss mov $0x7c00,%sp Sti push %ax 0x7C09 7 pop %es 0x7C0a 50 push %ax 0x7C0b 1f pop %ds 0x7C0c fc Cld 0x7C0d be1b7c mov $0x7c1b,%si 73 Comentario /*Establece ax=0*/ /*Establece ss=0*/ /*Establece sp=0x7C00*/ /*Activa Interrupciones*/ /*Apila el valor 0 (ax=0)*/ /*Des apila valor 0 y establece es=0*/ /*Apila el valor 0 (ax=0)*/ /*des apila valor 0 y establece ds=0*/ /*Limpia flag de dirección*/ /*Establece SI=0x7c1b 0x7c1b Es la dirección de memoria que se copiara a otra dirección.*/ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x7C10 bf1b06 mov $0x61b,%di 0x7C13 50 push %ax 0x7C14 57 push %di 0x7C15 b9e501 mov $0x1e5,%cx 0x7C18 f3a4 rep movsb %ds:(%si),%es:(%di) 0x7C1a cb Comentario /*Establece DI=0x61b 0x61b Es la dirección de memoria donde se almacenara el código que se copió anteriormente */ /*Apila el valor 0 (ax=0)*/ /*Apila el valor 0x61b (di=0x61b)*/ /*Establece cx=0x1e5 485 en hexadecimal /*Instrucción que copiara cx bytes de la dirección de si a di */ /*Instrucción que establecerá el valor de cs e ip con los valores de la apilados así: CS=0 IP=0x0x61b*/ Lret Tabla 16. NTLDR código fuente documentado parte 1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En resumen lo que la primera parte del código hace es copiar 445 bytes de información que se encuentra en la memoria partir de la dirección 0: 0x7c1b a la dirección 0: 0x61b y procede a ejecutar el código desde esta dirección. Se procede a desensamblar el código restante configurando la nueva dirección en la página web antes descrita. 3.4.2. 2. Segunda Parte Del Código Memoria Hexadecimal 0x061b bdbe07 Instrucción Ensamblador(GAS) mov $0x7be,%bp 0x061e b104 mov $0x4,%cl 0x0620 386 cmp %ch,0x0(%bp) 74 Comentario /*Establece bp=0x7be Ubicación de la primera entrada en la tabla de particiones*/ /*Estable cl=4 Máximo 4 entradas. Numero de particiones primarias*/ /*Compara el primer byte de la partición primaria con el valor de ch que es 0 para verificar si encuentra activa.*/ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x0623 7c09 jl 0x0000062e 0x0625 7513 jne 0x0000063a 0x0627 83c510 add $0x10,%bp 0x062a e2f4 loop 0x00000620 0x062c cd18 int $0x18 Comentario /*Si el valor del primer byte de la partición primaria es mayor que ch, esta sería la partición activa y continuamos revisando los parámetros de está dando un salto a la dirección 0:062e*/ /*Si el valor del primer byte de la primera partición primaria tampoco es igual a ch, esta sería una partición no valida y damos un salto a la dirección 0:063a*/ /*Adiciona 16 bytes al valor de bp para verificar si la siguiente partición primaria esta activa.*/ /*Salta a la dirección 0:0620 para buscar una partición primaria activa. La iteración la hace cl veces en este cl =4*/ /*Ejecuta int18h la cual indica un mensaje de error ya que no encontró ninguna partición primaria activa.*/ Tabla 17. NTLDR código fuente documentado parte 2. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En resumen la segunda parte del código intenta encontrar una partición primaria activa en la tabla de particiones. El primer byte de una entrada indica si es una partición activa (80 h) o no (00 h) cualesquiera otro valor significa que el registro de la tabla de partición no es válida. Si ninguno de los cuatro registros en la tabla de particiones está activo, se muestra el mensaje de error "no válido". Al encontrar un registro de partición activo valido continua con la siguiente sección de código. 75 3.4.2. 3. Tercera Parte Del Código Memoria Hexadecimal 0x062e 8bf5 Instrucción Ensamblador(GAS) mov %bp,%si 0x0630 83c610 add $0x10,%si 0x0633 49 dec %cx 0x0634 7419 je 0x0000064f 0x0636 382c cmp %ch,(%si) 0x0638 74f6 je 0x00000630 Comentario /*Establece el valor de si con la dirección del primer byte de la primera partición activa encontrada.*/ /*Adiciona 16 bytes al valor de la dirección que contiene si.*/ /*Decrementa el valor de cx para verificar si existen registros de particiones*/ /*Comprueba cuando cx llega a cero es decir ya no existen registros de particiones por comprobar y salta a la dirección 0:064f*/ /*Comprueba que el primer byte de las particiones que le siguen a la partición primaria activa con el valor de cx=0*/ /*Der ser el valor igual a cero salta a la dirección 0:0630 para buscar más registros de particiones.*/ Tabla 18. NTLDR código fuente documentado parte 3. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En resumen lo que la tercera parte de código comprueba que no haya más particiones activas de no haberlo salta a la quinta parte del código, caso contrario continua a la cuarta parte del código que es la siguiente. 76 3.4.2. 4. Cuarta Parte Del Código Memoria Hexadecimal 0x063a a0b507 Instrucción Ensamblador(GAS) mov 0x7b5,%al 0x063d b407 mov $0x7,%ah 0x063f 8bf0 mov %ax,%si 0x0641 ac lods %ds:(%si),%al 0x0642 3c00 cmp $0x0,%al 0x0644 74fc je 0x00000642 0x0646 bb0700 mov $0x7,%bx 0x0649 b40e mov $0xe,%ah 0x064b cd10 int $0x10 0x064d ebf2 jmp 0x00000641 Comentario /*Establece el valor de la dirección 0:07B5 a al en este caso el valor es 2c el primer byte de la sección definida por Windows.*/ /*Establece el valor de ah=0x07 */ Establece el valor de si con el de ax en este caso si = 0x72C /*Carga un byte del valor de la dirección ds:si al registro al y aumenta un byte así. Esto es pone el primer carácter del mensaje de error en el registro al*/ /*Compara el valor de al con 0 para verificar que ellos caracteres del mensaje de error se acabaron*/ /*Al acabar de imprimir el mensaje de error ejecuta un bucle infinito saltando a la dirección 0:0642*/ /*Establece el modo de texto y modo grafico*/ /*Estable la función de la int 10h*/ /*Ejecuta la interrupción de BIOS 10h*/ /*Salta a la posición de dirección 0:0641 para iterar los caracteres del mensaje de error*/ Tabla 19. NTLDR código fuente documentado parte 4. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En resumen la cuarta parte del código imprime un mensaje de error en la pantalla y genera un bucle infinito. 77 3.4.2. 5. Quinta Parte Del Código. Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x064f 884e10 mov %cl,0x10(%bp) 0x0652 e84600 call 0x0000069b 0x0655 732a jae 0x00000681 0x0657 fe4610 incb 0x10(%bp) 0x065a 807e040b cmpb $0xb,0x4(%bp) 0x065e 740b je 0x0000066b 0x0660 807e040c cmpb $0xc,0x4(%bp) 0x0664 7405 je 0x0000066b 0x0666 a0b607 mov 0x7b6,%al 0x0669 75d2 jne 0x0000063d 0x066b 0x066f 80460206 83460806 Comentario /*Establece el valor de cl a la dirección que almacena bp +16 bytes. En este caso cero.*/ /*Llama a la función almacenada en memoria que comienza en la posición 0x069b*/ /*Salta a la dirección 0:0681 si cf esta desactivada*/ /*Incrementa en byte de (bp+16) en esta caso 1*/ /*Verifica el sistema de archivos de la partición con 0xb partición fat32*/ /*Si la tabla de particiones es fat32 salta a la dirección 0:066b*/ /*Verifica el sistema de archivos de la partición con 0xc partición fat32 lba*/ /*Si la tabla de particiones es fat32 lba salta a la dirección 0:066b*/ /*Establece el valor de 0x7b6 a al*/ /*Salta a la dirección 0:063d. Para imprimir mensaje de error*/ addb $0x6,0x2(%bp) /*Adiciona el valor de 6 al registro de partición del número de la cabecera inicial de la partición*/ addw $0x6,0x8(%bp) /*Adiciona el valor de 6 al registro de partición del número de sectores en caso de soportar lba*/ 78 Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x0673 83560a00 adcw $0x0,0xa(%bp) 0x0677 e82100 call 0x0000069b 0x067a 7305 jae 0x00000681 0x067c a0b607 mov 0x7b6,%al 0x067f ebbc jmp 0x0000063d 0x0681 813efe7d55aa cmpw $0xaa55,0x7dfe 0x0687 740b je 0x00000694 0x0689 807e1000 cmpb $0x0,0x10(%bp) 0x068d 74c8 je 0x00000657 0x068f a0b707 mov 0x7b7,%al 0x0692 eba9 jmp 0x0000603d 0x0694 8bfc mov %sp,%di 0x0696 1e push %ds 0x0697 57 push %di 0x0698 8bf5 mov %bp,%si 79 Comentario /*Realiza la suma de cero +la dirección (bp+11). No hace nada */ /*Llama a la función 069b para leer el sector de la primera partición*/ /*Si la lectura tuvo éxito salta a la dirección 0681*/ /*Si la lectura no tuvo éxito establece al=0x7b6*/ /*Salta a la dirección 0:063d para imprimir mensaje de error*/ /*Compara el valor 0x55AA con el valor de la dirección 0x7DFE, el valor de la dirección 0:07dfe es 0x55AA la firma*/ /*Si la comparación anterior son iguales salta a la dirección 0x0694*/ /*Realiza la comparación entre el valor 0 y el valor de (bp+10). Al haber error de lectura la dirección (bp+16) aumenta un valor*/ /*Al ser (bp+16) cero se da otra oportunidad de lectura. Salta a la dirección 0:0657*/ /*Establece el valor 0:07b7 en al*/ /*Salta a la dirección 0:0603d para imprimir mensaje de error.*/ /*Establece el valor de sp a di. Ahora di tiene 0x7C00*/ /*Apila ds, Apila 0*/ /*Apila di, apila 0x07c00*/ /*Establece bp a si*/ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x069a cb lret 0x069b bf0500 mov $0x5,%di 0x069e 8a5600 mov 0x0(%bp),%dl 0x06a1 b408 mov $0x8,%ah 0x06a3 cd13 int $0x13 0x06a5 7223 jb 0x000006ca 0x06a7 8ac1 mov %cl,%al 0x06a9 243f and $0x3f,%al 0x06ab 98 cbtw 0x06ac 8ade mov %dh,%bl 80 Comentario /*Salta a la dirección apilada. 0:07C00. Ejecuta el primer sector de la partición primaria en este caso el VBR*/ /*Establece el valor de DI=5*/ /*Establece el valor de la dirección almacenada en bp a dl, en esta caso dl=0x80*/ /*Establece le valor ah=0x8, Establece la función 8 de la interrupción 13h*/ /*Ejecuta la interrupción 13h función 8. Obteniendo los parámetros del disco duro en este caso. ch # de cilindros, cl sectores por pista, dh # de cabeceras, dl # controlador y en la dirección es:di almacena 11 bytes con la información de la tabla base del disco.*/ /*Si la lectura de los parámetros del de la interrupción 13h dio error salta a la dirección 0:06ca*/ /*Establece el valor de cl a al. Al sectores por pista*/ /*Realiza un and 00111111 y al, ya que el número de sectores esta en los primeros 6 bits.*/ /*Establece el valor de al en ax.*/ /*Establece el valor de dh en bl, bl contiene ahora el número de cabeceras del disco.*/ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x06ae 8afc mov %ah,%bh 0x06b0 43 inc %bx 0x06b1 f7e3 mul %bx 0x06b3 8bd1 mov %cx,%dx 0x06b5 86d6 xchg %dl,%dh 0x06b7 b106 mov $0x6,%cl 0x06b9 d2ee shr %cl,%dh 0x06bb 42 inc %dx 0x06bc f7e2 mul %dx 0x06be 39560a cmp %dx,0xa(%bp) 0x06c1 7723 ja 0x000006e6 81 Comentario /*Establece el valor de ah a bh. En cualquier caso 0*/ /*Incrementa el valor de bx, bx contiene el número de cabeceras del disco.*/ /*Realiza la multiplicación de ax por bx. El número de caberas por sectores por pista. Y la almacena en dx:ax, en realidad solo en ax.*/ /*Establece el valor de cx a dx. Dx contiene el número de sectores por pista y el número de cilindros*/ /*Realiza un intercambio de datos entre dh, dl*/ /*Establece el valor de 6 a cl*/ /*Recorre 6 bits a la derecha el valor de dh. Ahora se tiene en dx el número de cilindros en los primeros 10 bits*/ /*Incrementa el valor de dx*/ /*Realiza la multiplicación de dx por ax, El número de cilindros por el número de cabeceras y sectores por pista.*/ /*Realiza la comparación entre dx y el valor al que apunta bp +10 bits, en este caso es el registro de tabla de particiones valor 00 00*/ /*Si la comparación de (bp+10) es mayor que dx salta a la dirección 6e6, La BIOS admite int13h extendida */ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x06c3 7205 jb 0x000006ca 0x06c5 394608 cmp %ax,0x8(%bp) 0x06c8 731c jae 0x000006e6 0x06ca b80102 mov $0x201,%ax 0x06cd bb007c mov $0x7c00,%bx 0x06d0 8b4e02 mov 0x2(%bp),%cx 0x06d3 8b5600 mov 0x0(%bp),%dx 0x06d6 cd13 int $0x13 0x06d8 7351 jae 0x0000072b 82 Comentario /*Si la comparación de (bp+10) es menor que dx salta a la dirección 6ca*/ /*Dada la comparación anterior fue igual compara (bp+8) con ax*/ /*Si (bp+8) es mayor o igual que ax salta a la dirección 0:06e6. La BIOS admite la int 13h extendida*/ /*Establece el valor ah=02, al=01, Parámetros de la interrupción 13h, función=02 y lectura de 01 sector.*/ /*Establece el valor de 0x7c00 a bx. Al ejecutar la int13h a partir de la dirección es:bx, se almacenara el sector leído.*/ /*Establece el valor del registro de particiones del número de cilindro y numero de sector en que inicia la partición a cx. El objetivo es leer el primer sector de la partición.*/ /*Establece el Controlador del registro de partición a dx. En el caso disco duro 80*/ /*Ejecuta la int 13h. Lee el primer sector de la partición primaria activa y lo almacena en memoria a partir de la dirección 0:07c00*/ /*Salta a la posición de memoria 0:072b si la lectura del disco tuvo éxito cf desactivada. Y retorna*/ Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x06da 4f dec %di 0x06db 744e je 0x0000072b 0x06dd 320000 xor %ah,%ah 0x06df 8a5600 mov 0x0(%bp),%dl 0x06e2 cd13 int $0x13 0x06e4 ebe4 jmp 0x000006ca Comentario /*La lectura del disco no tuvo éxito. Dec di*/ /*Comprueba que di haya llegado a cero y de ser así salta a la dirección 0:072b y retorna*/ /*Establece ah=0*/ /*Establece el valor al que apunta bp a dl. En este caso dl contiene el controlador del disco 80*/ /*Realiza la int 13 h función cero. Resetea el disco*/ /*Salta a la dirección 0:06ca, Para intentar volver a leer el disco*/ Tabla 20. NTLDR código fuente documentado parte 5. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En resumen la quinta parte del código lo que realiza es leer el primer sector de la partición primaria activa, lo carga a la posición 0x7c00 y le cede el control de procesamiento. La lectura del primer sector de la partición activa se la realiza en base a la especificación de su registro de la tabla de partición. En caso de encontrar error en la lectura realiza un reseteo del disco y vuelve a intentar una vez más si la segunda vez continua con error muestra el mensaje de error. También en la quinta parte del código verifica si los parámetros del registro de la tabla de particiones que esta como activo soporta lba y de ser así ejecuta la secta parte del código caso contrario lee el primer sector de la partición primaria en base a los parámetros de la especiación CHS que tiene el registro de la tabla de particiones. 83 3.4.2. 6. Sexta Parte Del Código Memoria Hexadecimal Instrucción Ensamblador(GAS) 0x06e6 8a5600 mov 0x0(%bp),%dl 0x06e9 60 pusha 0x06ea bbaa55 mov $0x55aa,%bx 0x06ed b441 mov $0x41,%ah 0x06ef cd13 int $0x13 0x06f1 7236 jb 0x000007029 0x06f3 81fb55aa cmp $0xaa55,%bx 0x06f7 7530 jne 0x000007029 0x06f9 f6c101 test $0x1,%cl 0x06fc 742b je 0x000007029 0x06fe 0x06ff 61 60 Popa pusha Comentario /*Establece el valor de (bp) a dl, en este caso 0x80 el controlador del driver*/ /*Apila ax*/ /*Establece el valor de 0x55aa en bx. Parámetros de la función extendida 13h*/ /*Establece el valor de 41 en ah. Parámetros de la función extendida 13h*/ /*Ejecuta al int 13h:CF Activada en error (no hay extensiones), limpia si no hay error AH = ?? Número de la versión mayor de las extensiones (01h = 1.x, 20h = 2.0 / EDD-1.0, 21h = 2.1 / EDD-1.1, 30h = EDD-3.0) AL = ?? Uso Interno BX = AA55h Devuelve AA55h si están instaladas CX = ?? Lista de bits de las extensiones instaladas (Bit 0-15) DH = ?? Versión de las extensiones (v2.0,no presente en 1.x)*/ /*Salta a la dirección 0:0729 3n caso de error de lectura.*/ /*Compara el valor aa55 con el valor de bx para ver si están instaladas la extensiones de la int13h*/ /*Si la comparación anterior no son iguales salta a la posición 0:0729, Indica error en la lectura*/ /*Realiza una comparación ente 0001 y el valor de cl.*/ /*Si en la comparación anterior cl es menor o igual a 1 salta a la dirección 0:0129 para dar un mensaje de error*/ /*Des apila ax*/ /*Apila ax*/ 84 Memoria Hexadecimal Instrucción Ensamblador(GAS) Comentario 0x7000 6a00 push $0x0 /*Apila cero*/ 0x7002 6a00 push $0x0 /*Apila cero*/ /*Apila el valor de (bp+10) primera parte del valor del sector 0x7004 ff760a pushw 0xa(%bp) en que inicia la partición primaria que soporta lba*/ /*Apila el valor de (bp+10) segunda parte del valor del sector 0x7007 ff7608 pushw 0x8(%bp) en que inicia la partición primaria que soporta lba*/ 0x700a 6a00 push $0x0 /*Apila el numero 0: No se usa*/ 0x700c 68007c push $0x7c00 /*Apila el número 07c00*/ /*Apila el numero 1: Numero de 0x700f 6a01 push $0x1 sectores a leer*/ /*Apila el número 16, tamaño del 0x7011 6a10 push $0x10 DAP. Disk Address Packet*/ 0x7013 b442 mov $0x42,%ah /*Establece el 0x42 en ah. */ /*Establece el valor de sp a sí. 0x7015 8bf4 mov %sp,%si Ahora si 0x7c00*/ /*Ejecuta la int 13 con función 42h, Lee el primer sector de la 0x7017 cd13 int $0x13 partición primaria y lo almacena en la dirección 0:07c00*/ /*Des apila y su valor lo pone en 0x701a 61 Popa ax*/ /*Si la lectura tuvo éxito salta a la 0x701b 730e jae 0x00000702b posición 0:0720b*/ /*La lectura no tuvo éxito y 0x701d 4f dec %di decrementa di*/ /*Si di =0 retorna con error ya que 0x701e 740b je 0x00000702b se activa cf*/ 0x7020 320000 xor %ah, %ah /*Establece ah=0*/ /*Establece el valor de bp a dl, en 0x7022 8a5600 mov 0x0(%bp),%dl este caso el controlador*/ 0x7025 cd13 int $0x13 /*Ejecuta la interrupción 13 h función 0, Respeta el disco*/ 0x7027 ebd6 jmp 0x000006ff /*Intenta nuevamente la lectura del disco. Saltando a l 0:06ff*/ 0x702a f9 Stc 0x702b c3 /*Activa la bandera de acarreo para indicar error de lectura*/ /*Termina y retorna*/ Ret Tabla 21. NTLDR código fuente documentado parte 6. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 85 En resumen la sexta parte del código se trata cuando la BIOS soporta la función extendida 13h, Y se procede a leer el primer de la partición primaria leyendo los parámetros de la sección lba. Y se procede almacenar el primer sector a la dirección 0:07c00. 3.4.3. Alcance estudio NTLDR El alcance del estudio del gestor de arranque del NTLDR es solo de la sección que corresponde al MBR. El MBR del gestor de arranque NTLDR tiene como objetivo cargar a memoria el VBR que no se examinara. Solo se dirá que el VBR contiene el OEM ID (id de la empresa manufacturera), la BPB (BIOS Parameter Block) y el código para encontrar y cargar el kernel de Windows. 3.5 GRUB LEGACY 3.5.1 Introducción GRUB GNU GRUB es un gestor de arranque muy potente, que puede cargar una gran variedad de sistemas operativos libres, así como sistemas operativos propietarios con un método denominado Chain Loading. Una de las características importantes de GRUB es la flexibilidad, GRUB entiende varios sistemas de archivos y formatos ejecutables del núcleo, por lo que puede cargar un sistema operativo, sin registrar la posición física de su núcleo en el disco. De este modo se puede cargar el kernel sólo especificando su nombre de archivo y la unidad y la partición donde reside el kernel. Al arrancar con GRUB, puede utilizar una interfaz de línea de comandos o una interfaz de menú. Mediante la interfaz de línea de comandos se debe escribir la especificación de la unidad y el nombre de archivo del kernel manualmente. En la interfaz de menú, sólo tiene que seleccionar un sistema operativo con las teclas de flecha. El menú se basa en un archivo de configuración que se prepara de antemano. Mientras que en el menú se puede cambiar al modo de línea de comandos, y viceversa. Se puede editar las entradas del menú antes de usarlos. 86 3.5.2 Historia de GRUB GRUB se originó en 1995, cuando Eric Boleyn estaba tratando de arrancar el GNU Hurd con la Universidad de Utah Mach 4 microkernel (ahora conocido como GNU Mach). Erich y Brian Ford diseñaron el Multiboot, porque estaban decididos a no añadir a la gran cantidad de métodos de arranque PC mutuamente incompatibles. Erich comenzó modificando el gestor de arranque de FreeBSD para que soportara arranque múltiple. Pronto se dio cuenta de que sería mucho más fácil de escribir su propio gestor de arranque desde cero que seguir trabajando en el gestor de arranque de FreeBSD, y así inicio GRUB. 3.5.3 Características de GRUB El requisito principal para GRUB es que sea compatible con la especificación de arranque múltiple. Los otros objetivos, enumerados en el orden aproximado de importancia, son: Funciones básicas deben ser sencillo para los usuarios finales. Funcionalidad rica para apoyar expertos del kernel y diseñadores. La compatibilidad hacia atrás para arrancar FreeBSD, NetBSD, OpenBSD y Linux. Núcleos de propiedad (como DOS, Windows NT y OS / 2) son compatibles a través de una función de la cadena de carga. A excepción de los modos específicos de compatibilidad ((chain-loading and the Linux piggyback format), todos los núcleos se iniciarán en el mismo estado que en el Multiboot Specification. Sólo los núcleos cargados a 1 megabyte o superior están actualmente soportados. Cualquier intento de cargar por debajo de ese límite simplemente resultar en una falla inmediata y un mensaje de informe de errores el problema. Además de las características anteriores, GRUB tiene las siguientes características: 87 Reconocer múltiples formatos ejecutables.- Apoyo muchas de las variantes más a.out ELF. Las tablas de símbolos también se cargan. Apoyar kernels no Multiboot.- Apoyar muchos de los diferentes núcleos de 32 bits libres que carecen de cumplimiento de arranque múltiple (principalmente FreeBSD, NetBSD, OpenBSD y Linux). Chainloading de otros gestores de arranque también es compatible. Módulos múltiples de carga.- Totalmente compatible con la función de arranque múltiple de cargar varios módulos. Cargar un archivo de configuración.- Apoyar a un archivo de configuración de texto legible por humanos con comandos de arranque predefinidos. También puede cargar otro archivo de configuración dinámica e incrustar un archivo de configuración preestablecida en un archivo de imagen de GRUB. La lista de comandos son un superconjunto de comandos admitidos en la línea Proporcionar una interfaz de menú.- Una interfaz de menú con comandos de arranque predefinidos, con un tiempo de espera programable. No hay límite fijo en el número de entradas de arranque. Tiene una interfaz de línea de comandos flexibles.- Una interfaz de línea de comandos bastante flexible, accesible desde el menú, está disponible para editar los comandos predefinidos, o escribir un nuevo comando de arranque establecido a partir de cero. Si no hay ningún archivo de configuración está presente, GRUB cae a la línea de comandos. Soporte de múltiples tipos de sistemas de archivos.- Soporte de múltiples tipos de sistemas de ficheros de forma transparente, además de una notación de lista de bloques explícito útil. Los tipos de sistemas de archivos soportados son BSD FFS, DOS FAT16 y FAT32, Minix fs, ext2fs Linux, ReiserFS, JFS, XFS, y VSTA fs. Soporte descompresión automática.- Puede descomprimir archivos que se comprimieron por gzip. Esta función es a la vez automática y transparente para el usuario (es decir, todas las funciones operan en el 88 contenido sin comprimir de los archivos especificados). Esto reduce considerablemente el tamaño del archivo y la carga del tiempo, una particular gran beneficio para disquetes. Es concebible que algunos módulos del núcleo se deben cargar en un estado comprimido, por lo que un comando del módulo de carga diferente se puede especificar para evitar la descompresión de los módulos. Acceder a los datos en cualquier dispositivo instalado.- La lectura de datos de soporte de cualquiera o todos los disquetes o disco duro (s) reconocido por la BIOS, independientemente del ajuste del dispositivo raíz. Ser independiente de las traducciones de la geometría de unidad.- A diferencia de muchos otros gestores de arranque, GRUB hace que la traducción en particular unidad irrelevante. Una unidad instalada y funcionando con una traducción se puede convertir en otra traducción, sin efectos adversos o cambios en la configuración de GRUB. Detectar todas RAM instalada.- GRUB generalmente puede encontrar toda la memoria RAM instalada en una máquina compatible con PC. Utiliza una técnica de consulta BIOS avanzada para encontrar todas las regiones de memoria. Apoyo a modo de Dirección de bloque lógico.- En las llamadas de disco tradicionales (llamado modo CHS), hay un problema de traducción de geometría, es decir, la BIOS no puede acceder a más de 1024 cilindros, por lo que el espacio accesible se limita a al menos 508 MB y un máximo de 8 GB. GRUB no puede resolver este problema universalmente, ya que no hay interfaz estándar utilizado en todas las máquinas. Sin embargo, varias máquinas más nuevas tienen el modo de interfaz nueva, direcciones de bloques lógicos (LBA). GRUB detecta automáticamente si el modo LBA está disponible y lo usa si está disponible. En el modo LBA, GRUB puede acceder a todo el disco. 89 El arranque de red de apoyo.- GRUB es básicamente un gestor de arranque basado en disco, pero también tiene soporte de red. Puede cargar imágenes del sistema operativo de una red mediante el protocolo TFTP. Apoyar terminales remotos.- Para apoyar a los ordenadores sin consola, GRUB proporciona soporte del terminal remoto, de modo que usted puede controlar GRUB desde un host remoto. Sólo el apoyo terminal serie se implementa en el momento. Convención de nomenclatura de GRUB La forma de especificar una unidad / partición es la siguiente: En primer lugar, GRUB requiere que el nombre del dispositivo este separado por una coma del número de partición y los dos deben encerrarse con (), el número de partición omite para referirse a toda la unidad física. Los nombres de los dispositivos son: fd0, fd1, fdn significa que es un disquete, n es el n-esimo número de unidad. hd0, hd1, hdn significa que es un disco duro, n es el n-esimo número de unidad. El número de partición: 0,1,2,….n significa la n-esima partición del disco. Ejemplos: (Fd0) El número '0' es el número de la unidad, que se contará a partir de cero. Esta expresión significa que GRUB usará todo el disco. 90 (Hd0,1) Aquí, hd significa que es una unidad de disco duro. El primer entero 0 indica el número de la unidad, es decir, el primer disco duro, mientras que el segundo entero 1, indica el número de partición (o el número de segmento pc en la terminología BSD). Una vez más, se debe tener en cuenta que los números de partición se cuentan desde cero, no de uno. Esta expresión significa la segunda partición de la primera unidad de disco duro. En este caso, GRUB utiliza una partición del disco, en lugar de todo el disco. (Hd0,4) Especifica la primera partición extendida de la primera unidad de disco duro. Tenga en cuenta que los números de partición para particiones extendidas se cuentan desde `4 ', independientemente del número real de particiones primarias en el disco duro. (Hd1, a) Esto significa el BSD partición „a‟ del segundo disco duro. Si se necesita especificar qué número de segmento PC se debe utilizar, se debe usar (hd1,0, a) . Si el número de segmento pc se omite, búsquedas de GRUB de la primera partición pc que tiene un BSD „a‟ partición. Por supuesto, para acceder en realidad los discos o particiones con GRUB, es necesario utilizar la especificación del dispositivo en un comando, como: ‘root (fd0)’ o ‘unhide (hd0,2)’ Para averiguar qué número especifica una partición que desea, la línea de comandos de GRUB se tiene la opción de completar el argumento. Esto significa que, por ejemplo, sólo se tiene que escribir: ‘root (‘ Seguido un <TAB>, y GRUB mostrará la lista de unidades, particiones o nombres de archivos. Por lo tanto, es bastante fácil de determinar el nombre de la partición de destino, incluso con un mínimo conocimiento de la sintaxis. 91 Nota: Se debe tener en cuenta que GRUB no distingue entre IDE SCSI. GRUB cuenta el número de unidades desde cero, independientemente de su tipo. Normalmente, cualquier número de unidad IDE es menor que cualquier número de unidades SCSI, aunque eso no es cierto si se cambia la secuencia de arranque mediante el canje de IDE y SCSI en el BIOS. Para especificar un archivo considere el siguiente ejemplo: ‘(Hd0,0) / vmlinuz’ Especifica el archivo llamado „vmlinuz ', que se encuentra en la primera partición del primer disco duro. Se debe tener en cuenta que la realización argumento funciona con nombres de archivo, también. 3.5.4 Creación de un disquete de arranque GRUB Para pode crear un disquet de arranque GRUB tenemos algunas opciones: Tener instalado la versión de GRUB en el disco duro que se le va a copiar a disco. Veamos un ejemplo suponiendo que tenemos instalado Linux en una versión de 32 bits y su gestor de arranque GRUB: # cd /usr/lib/grub/i386-pc dd if=stage1 of=/dev/fd0 bs=512 count=1 1+0 records in 1+0 records out # dd if=stage2 of=/dev/fd0 bs=512 seek=1 153+1 records in 153+1 records out Descargar el código de la versión de GRUB que se desee compilar y generar los ejecutables, copiarlos al disquet. Esta opción se verá en detalle en la opción de creación de ejecutables de GRUB. Iniciar un cd con GRUB y por medio de comandos copiarlos al disquet. 92 3.5.5 Realizar un CD-ROM Booteable con GRUB GRUB soporta el modo no emulación en la especificación El Torito 5. Esto significa que se puede utilizar el CD-ROM de GRUB y no se tiene que hacer un archivo de imagen de disco flexible o disco, que pueda causar problemas de compatibilidad. Para arrancar desde un CD-ROM, GRUB usa una Etapa 2 especial llamada stage2_eltoritol. Los únicos archivos GRUB que se necesita habilitar en el CDROM de arranque son stage2_eltorito y opcionalmente un archivo de configuración menú.lst. No es necesario utilizar stage1 o stage2, porque El Torito es bastante diferente del proceso de arranque estándar. Ejemplo de procedimientos para hacer una imagen de CD-ROM de arranque, suponiendo que tengo instalado una distribución del sistema operativo Linux de 32 bits y como gestor de arranque GRUB. En primer lugar se debe de hacer un directorio superior de la imagen de arranque, por ejemplo „iso‟: $ mkdir iso Crear un directorio para GRUB: $ mkdir -p iso / boot / grub Copiar el archivo stage2_eltorito: $ cp /usr/lib/grub/ i386-pc/stage2_eltorito 93 iso/boo/grub Si se desea, hacer que el archivo de configuración menu.lst este bajo iso/boo / grub y copiar todos los archivos y directorios para el disco en el directorio iso /. Por último, se debe hacer un archivo de imagen ISO9660 así: $ mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot \ -boot-load-size 4 -boot-info-table -o grub.iso iso Esto produce un archivo llamado grub.iso, que luego se puede quemar en un CD (o DVD). Puede utilizar el dispositivo `(cd) 'para acceder a un CD-ROM en su archivo de configuración. Esto no es necesario; GRUB ajusta automáticamente el dispositivo raíz a `(cd) 'al arrancar desde un CD-ROM. Sólo es necesario hacer referencia a `(cd) 'si quiere acceder a otras unidades también. Instalación de GRUB de forma nativa Precaución: La instalación stage1 de GRUB de esta manera, borrará el sector de arranque normal utilizado por el sistema operativo. GRUB actualmente puede arrancar GNU Mach, Linux, FreeBSD, NetBSD, y OpenBSD directamente. Para instalar GRUB en el entorno nativo de la pc se se tendrá que utilizar un disco de arranque GRUB, un CD-ROM de arranque GRUB y reiniciar el equipo con él Disco o del CD-ROM Al encender la pc, GRUB se auto iniciará y mostrará la interfaz de línea de comandos. En primer lugar, se debe establecer como dispositivo raíz de GRUB, la partición que contiene el directorio de arranque, o el dispositivo de arranque así: grub> root (hd0,0) 94 Al no estar seguro de qué partición ocupa este directorio, Se debe utilizar el comando find así: grub> find / boot / grub / stage1 El comando find buscará el nombre del archivo / boot / grub / stage1 y mostrara los dispositivos que contienen el archivo. Una vez que se haya configurado correctamente el dispositivo raíz, se debe ejecutar el comando setup. grub> setup (hd0) Este comando instalará el gestor de arranque GRUB en el Master Boot Record (MBR) de la primera unidad. Si se quiere poner GRUB en el sector de arranque de una partición en lugar de ponerlo en el primer sector de la unidad, especifique la partición en la que desea instalar GRUB. grub> setup (hd0,0) Después de utilizar el comando de instalación. Se debe iniciar la pc sin el disquete o CD-ROM. Instalación de GRUB utilizando grub-install Precaución: Este procedimiento es menos seguro, porque hay varias formas en las que el equipo puede llegar a no arrancar. Por ejemplo, la mayoría de sistemas operativos no tienen métodos en el que GRUB puede mapear los drivers de la BIOS correctamente. En estos casos GRUB asimila datos por defecto. Esto tendrá éxito en la mayoría de los casos, pero no siempre. Por lo tanto, GRUB le proporciona un archivo de mapa llamado el mapa de dispositivos, que se debe corregir si es incorrecto. 95 Para instalar GRUB utilizando el comando grub-install se debe poner como argumento el dispositivo o la partición en la que se instalara GRUB. Por Ejemplo: # Grub-install / dev / hda # Grub-install '(hd0)' # Grub-install hd0 Para la instalación el Disco Floppy # Mke2fs / dev / fd0 # Mount -t ext2 / dev / fd0 / mnt # Grub-install --root-directorio = / mnt fd0 # Umount / mnt Para unidades que se montan se debe utilizar el comando: # Grub-install-directorio --root = / boot / dev / had Se debe tener en cuenta que grub-install es en realidad sólo una secuencia de comandos de shell y la verdadera tarea es realizada por el shell de grub. Arranque de un Sistema Operativo GRUB puede cargar núcleos compatibles con Multiboot de una manera consistente, sin embargo existen Sistemas Operativos libres que tengan que usarce métodos especiales. GRUB tiene dos métodos de arranque distintos que son carga directa y aplicando chain-loadin. En términos generales, la carga directa es más conveniente, ya que no es necesario instalar ni mantener otros gestores de arranque. GRUB es lo suficientemente flexible como para cargar un sistema operativo desde un disco / partición arbitraria. Sin embargo, el método chain-loading es necesario ya que GRUB no soporta todos los sistemas operativos existentes de forma nativa. 96 Carga Directa Grub Utiliza el Multiboot especification. GRUB puede arrancar cualquier sistema operativo de arranque múltiplecompatible con los siguientes pasos: Establecer el dispositivo raíz de GRUB a la unidad donde las imágenes del sistema operativo se almacenan con el comando root. Cargar la imagen del núcleo con el comando kernel. Si se necesita módulos, estos se deben cargar con el comando module o modulenounzip. Ejecutar el comando boot. 4.1.2 Carga otro gestor de arranque para arrancar sistemas operativos no compatibles Método Chain-loading Para arrancar un sistema operativo no compatible (por ejemplo, Windows 95, xp vista etc ), se debe utilizar el método chain-loading que lo que realiza es cargar a memoria el vbr del sistema operativo y transferirle el control. Los pasos para cargar y ejecutar el método Chain-Loading son: Establecer el dispositivo raíz de GRUB a la partición por medio del comando rootnoverify así: grub> rootnoverify (hd0,0) Activar la bandera en la partición usando el comando makeactive. grub> makeactive 97 Cargar el gestor de arranque de la partición ejecutando el comando chainloader grub> chainloader +1 El argumento +1 en el comando chianloader indica que se deber leer y cargar a memoria el tamaño exacto de un sector o 512 bytes, de la primera partición activa. Configuración Grub usa un archivo de configuración para crear la lista en la interfaz de menú de GRUB de los sistemas operativos para el arranque, básicamente permite al usuario seleccionar un grupo predefinido de comandos para su ejecución. Para activar el menú de GRUB se necesita que el archivo de configuración este en el directorio de arranque. Como ejemplo se estudiara un archivo de configuración: El archivo de configuración debe contener configuraciones generales. Estructura del archivo de configuración El archivo de configuración de la interfaz de menú de GRUB es /boot/grub/grub.conf. Los comandos para configurar las preferencias globales para la interfaz de menú están ubicados al inicio del archivo, seguido de las diferentes estrofas para cada sistema operativo o kernels listados en el menú. El siguiente es un ejemplo de archivo de configuración de menú de GRUB muy básico diseñado para arrancar bien sea Red Hat Enterprise Linux o Microsoft Windows 2000: 98 default=0 timeout=10 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title Red Hat Enterprise Linux AS (2.6.8-1.523) root (hd0,0) kernel /vmlinuz-2.6.8-1.523 ro root=/dev/VolGroup00/LogVol00 rhgb quiet initrd /initrd-2.6.8-1.523.img # section to load Windows title Windows rootnoverify (hd0,0) chainloader +1 Tabla 22. Archivo de Configuración de Menú de GRUB. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Default <opción> Indica que la primera opción title se ejecutara por defecto en este caso iniciara Red Hat Enterprise Linux como el sistema operativo predeterminado. Timeout <tiempo> Indica el tiempo de espera que tiene el usuario para seleccionar una opción de arranque, si el tiempo de espera se consume en su totalidad se seleccionara la opción por defecto selecciona en default. En este caso le dará al usuario una espera de 10 segundos para seleccionar un sistema operativo diferente a Red Hat y que establezca un arranque automático después de 10 segundos. Se proporcionan dos secciones, una para cada entrada de sistema, con comandos específicos para la tabla de partición del sistema. Chainloader </ruta/a/archivo> Carga el archivo especificado como gestor de encadenamiento. Se debe reemplazar </ruta/a/archivo> con la ruta absoluta al gestor de encadenamiento. 99 Si el archivo está ubicado en el primer sector de la partición especificada, puede utilizar la notación de lista de bloques, +1. Color <color-normal> <color-seleccionado> Le permite configurar los colores específicos que se usarán en el menú. Se configuran dos colores: uno de fondo y otro de primer plano. Use nombres de colores simples, tales como red/black para rojo/negro. Fallback <entero> El parámetro <entero> es el número del título de la entrada que deberá probarse si falla el primer intento. Hiddenmenu Si se utiliza, no se podrá mostrar la interfaz de menú de GRUB, cargando la entrada default (predeterminada) cuando caduca el período timeout (tiempo de espera). El usuario puede ver el menú estándar de GRUB si pulsa la tecla [Esc]. Initrd </ruta/a/initrd> Permite a los usuarios especificar un disco RAM inicial para utilizarlo al arrancar. Se debe reemplazar </ruta/a/initrd> con la ruta absoluta al disco RAM inicial. Kernel </ruta/a/kernel> <opción-1> <opción-N> Especifica el archivo del kernel a cargar cuando se arranca el sistema operativo. Se pueden pasar múltiples opciones al kernel cuando éste se cargue. Password=<contraseña> Si se utiliza, el usuario que no conozca la contraseña no podrá modificar las entradas de esta opción de menú de GRUB. Opcionalmente, se puede especificar un archivo de configuración de menú alternativo después de la directriz password=<contraseña>. En este caso, 100 GRUB reiniciará la etapa 2 del gestor de arranque y utilizará este archivo de configuración alternativo para crear el menú. Si se omite este archivo de configuración alternativo del comando, el usuario que sepa la contraseña podrá modificar el archivo de configuración actual. Root (<tipo-dispositivo><numero-dispositivo>,<partición>) Configura la partición raíz para GRUB, tal como (hd0,0) y monta la partición. Rootnoverify (<tipo-dispositivo><numero-dispositivo>,<partición>) Configura la partición raíz para GRUB, tal como el comando root pero no monta la partición. Splashimage=<ruta-a-imagen> Especifica la ubicación de la imagen de pantalla splash que se utilizará al arrancar. Title <título-de-grupo> Establece un título que se utilizará con un grupo de comandos concreto para cargar un sistema operativo. 3.5.5 Construcción y Compilación de GRUB Grub al ser software libre se cuenta con el código para su estudio y modificación, así los requisitos necesarios en que se construyó y compilo son los siguientes: Sistema Operativo Host: Windows 7 de 64 bits. Virtualizador: Virtual Box versión 4.3.20 Sistema Operativo Guest: GNU Linux Centos de 32 bits versión 6.5 Versión de gcc Red Hat 4.4.7-11 Versión de binutils-2.20.51.0.2-5.42.el6.i68 grub-0.97.tar.gz 101 Proceso Una vez obtenido grub-0.97.tar.gz a través del sitio ftp: ftp://alpha.gnu.org/gnu/grub/grub-0.97.tar.gz, y colocado en algún directorio del Sistema Operativo Centos. 1. Se debe abrir una terminal. Figura 29. Terminal en Modo Grafico. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 2. Por medio del comando cd se debe posicionar en la carpeta en que se encuentra el archivo comprimido grub-0.97.tar.gz. En el caso del ejemplo se encuentra en el directorio de descarga de root. Figura 30. Comando cd. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 102 3. Se procede a desempaquetar y descomprimir GRUB versión 0.97, con el comando siguiente comando: zcat grub-0.97.tar.gz | tar xvf – Figura 31. Comando zcat. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Lo cual indicara en la salida de la terminal que se crearon archivos adicionales. Figura 32. Ejecución del comando zcat. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 103 En el caso de ejemplo se creó un Directorio de nombre grub-0.97 dentro del directorio de descargas. Figura 33. Creación del directorio grub-097. Autor: Tesista. Fuente: Desarrollo de tema de tesis. El directorio grub-0.97 es el descomprimido y tiene todas las fuentes de grub. Figura 34. Contenido del directorio grub-097. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 104 Para verificar que archivos se crean, se tomara como ejemplo el subdirectorio de grub stage1. Figura 35. Archivos del directorio stage1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 4. Ingresamos al directorio de grub-0.97 por medio del comando cd cd grub-0.97 Figura 36. Ingreso Subdirectorio Grub-0.97. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En este paso podemos revisar los archivos makefile, el directorio stage1, stage2 y el código de los diferentes archivos, compilarlos como se desee en forma individual y global. Para el caso de estudio se lo realizara de forma global. 105 5. Ejecutamos el archivo de configuración global con el comando: ./configure CC=gcc34 Figura 37. Ejecución de ./configure CC=gcc34 Autor: Tesista. Fuente: Desarrollo de tema de tesis. La ejecución crea archivos adicionales en el directorio grub-0.97, modifica archivos makefile que permiten la construcción de los ejecutables e imagines binarias del código de grub. Figura 38. Listado de ./configure CC=gcc34. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 106 6. Ejecutamos el archivo install que se configuro con el comando anterior así: # make install Figura 39. Ejecución del archivo install. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Figura 40. Salida del comando make install. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 107 Como se observa en la salida de la terminal se crearon más archivos dentro del directorio y subdirectorios de grub-0.97. Algunos de estos archivos son los ejecutable e imagines binarias puras que se puede utilizar para crear discos, CD-ROM arrancables. Para el caso de uso se observara el subdirectorio stage1 de grub-0.97 Como se observa en la figura anterior se tiene los archivos makefile: MakeFile, MakeFile.am, MakeFile.in El código fuente: Stage1.h, stage1.S Un archivo objeto: Stage1.o Un archivo ejecutable: Stage1.exec Una imagen binaria pura: Stage1 A excepción del código fuente los demás archivos se crearon a partir de ejecutar el archivo de configuración global y el archivo de instalación global. 3.5.6 Estudio del Código de GRUB Para realizar un estudio detallado del funcionamiento de GRUB se aplicara técnicas de ingeniería inversa a la imagen pura de la primera etapa y se compara con el código libre que proporciona grub, para verificar como funciona. El código fuente de la primera etapa de GRUB consta de dos archivos el stage1.h y el stage1.S. El primero es el archivo de cabecera en donde se definen las constantes, parámetros y demás atributos usados en stage1.S. Se unirá ambos archivos en uno solo para realizar la comparación del código. 108 3.5.6 .1 Estudio Del Código De La Primera Etapa La primera etapa de GRUB es el MBR de grub, la imagen binaria que en la primera etapa se crea se debe almacenar o inyectar en el primer sector o sector de arranque del dispositivo. Así la imagen binaria de la primera etapa debe tener un tamaño exacto de 512 bytes y terminar con la firma que caracteriza a un MBR que es el código hexadecimal 0x55AA. Código En Hexadecimal El código hexadecimal de la imagen binaria pura que se creó al construir grub es: Figura 41. Código hexadecimal de GRUB Primera Etapa. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 109 Como se observa en la figura anterior la primera etapa de GRUB tiene un tamaño de 512 bytes y sus dos últimos bytes son 0x55AA, es decir su código es característico de un gestor de arranque. Al aplicar la herramienta de Ingeniería Inversa a la imagen binaria de la primera etapa de GRUB con la página web: http://www2.onlinedisassembler.com/odaweb/, Obtendremos el código en lenguaje ensamblador. Así configuramos la página web con los parámetros en que se inicia un gestor de arranque y desensamblamos GRUB. Figura 42. Configuración des ensamblaje. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Al desensamblar y eliminar las partes que no son código ensamblador tenemos: Dirección .data:0x00007C00 .data:0x00007C02 .data:0x00007C4a .data:0x00007C4b .data:0x00007C4d .data:0x00007C50 .data:0x00007C52 .data:0x00007C54 .data:0x00007C59 .data:0x00007C5b Hexadecimal eb48 90 fa eb07 f6c280 7502 b280 ea597c0000 31c0 8ed8 110 Ensamblador jmp 0x00007c4a nop cli jmp 0x00007c54 test $0x80,%dl jne 0x00007c54 mov $0x80,%dl ljmp $0x0,$0x7c59 xor %ax,%ax mov %ax,%ds Dirección .data:0x00007C5d .data:0x00007C5f .data:0x00007C62 .data:0x00007C63 .data:0x00007C66 .data:0x00007C68 .data:0x00007C6a .data:0x00007C6c .data:0x00007C6d .data:0x00007C70 .data:0x00007C73 .data:0x00007C76 .data:0x00007C78 .data:0x00007C7a .data:0x00007C7d .data:0x00007C7f .data:0x00007C80 .data:0x00007C81 .data:0x00007C83 .data:0x00007C87 .data:0x00007C89 .data:0x00007C8c .data:0x00007C8e .data:0x00007C90 .data:0x00007C93 .data:0x00007C95 .data:0x00007C99 .data:0x00007C9c .data:0x00007Ca0 .data:0x00007Ca5 .data:0x00007Ca9 .data:0x00007Cae Hexadecimal 8ed0 bc0020 fb a0407c 3cff 7402 88c2 52 be7f7d e83401 f6c280 7454 b441 bbaa55 cd13 5a 52 7249 81fb55aa 7543 a0417c 84c0 7505 83E103 7437 668b4c10 be057c c644ff01 668b1e447c c7041000 c744020100 66895c08 .data:0x00007Cb2 c744060070 .data:0x00007Cb7 .data:0x00007Cba .data:0x00007Cbd .data:0x00007Cc1 .data:0x00007Cc3 .data:0x00007Cc5 .data:0x00007Cc7 .data:0x00007Cca .data:0x00007Ccc 6631c0 894404 6689440c b442 cd13 7205 bb0070 eb7d b408 111 Ensamblador mov %ax,%ss mov $0x2000,%sp sti mov 0x7c40,%al cmp $0xff,%al je 0x00007c6c mov %al,%dl push %dx mov $0x7d7f,%si call 0x000001a7 test $0x80,%dl je 0x00007ccc mov $0x41,%ah mov $0x55aa,%bx int $0x13 pop %dx push %dx jb 0x00007ccc cmp $0xaa55,%bx jne 0x00007ccc mov 0x7c41,%al test %al,%al jne 0x00007c95 and $0x1,%cx je 0x00007ccc mov 0x10(%si),%ecx mov $0x7c05,%si movb $0x1,-0x1(%si) mov 0x7c44,%ebx movw $0x10,(%si) movw $0x1,0x2(%si) mov %ebx,0x8(%si) movw $0x7000,0x6(%si) xor %eax,%eax mov %ax,0x4(%si) mov %eax,0xc(%si) mov $0x42,%ah int $0x13 jb 0x00007ccc mov $0x7000,%bx jmp 0x00000149 mov $0x8,%ah Dirección .data:0x00007Cce .data:0x00007Cd0 .data:0x00007Cd2 .data:0x00007Cd5 .data:0x00007Cd9 .data:0x00007Cdc .data:0x00007Cdf .data:0x00007Ce3 .data:0x00007Ce6 .data:0x00007Ce8 .data:0x00007Ce9 .data:0x00007Ced .data:0x00007Cef .data:0x00007Cf1 .data:0x00007Cf4 .data:0x00007Cf6 .data:0x00007Cf8 .data:0x00007Cf9 .data:0x00007Cfc .data:0x00007Cfe .data:0x00007D00 .data:0x00007D03 .data:0x00007D06 .data:0x00007D0a .data:0x00007D0d .data:0x00007D10 .data:0x00007D13 .data:0x00007D16 .data:0x00007D1a .data:0x00007D1d .data:0x00007D20 .data:0x00007D23 .data:0x00007D25 .data:0x00007D28 .data:0x00007D2b .data:0x00007D2e .data:0x00007D30 .data:0x00007D32 .data:0x00007D35 .data:0x00007D36 .data:0x00007D39 .data:0x00007D3c .data:0x00007D3e Hexadecimal cd13 730a f6c280 0f84ea00 e98d00 be057c c644ff00 6631c0 88f0 40 66894404 31d2 88ca c1e202 8,80E+09 88f4 40 894408 31c0 88d0 c0e802 668904 66a1447c 6631d2 66f734 88540a 6631d2 66f77404 88540b 89440c 3b4408 7d3c 8a540d c0e206 8a4c0a fec1 08d1 8a6c0c 5a 8a740b bb0070 8ec3 31db 112 Ensamblador int $0x13 jae 0x00007cdc test $0x80,%dl je 0x000001c3 jmp 0x00000169 mov $0x7c05,%si movb $0x0,-0x1(%si) xor %eax,%eax mov %dh,%al inc %ax mov %eax,0x4(%si) xor %dx,%dx mov %cl,%dl shl $0x2,%dx mov %ch,%al mov %dh,%ah inc %ax mov %ax,0x8(%si) xor %ax,%ax mov %dl,%al shr $0x2,%al mov %eax,(%si) mov 0x7c44,%eax xor %edx,%edx divl (%si) mov %dl,0xa(%si) xor %edx,%edx divl 0x4(%si) mov %dl,0xb(%si) mov %ax,0xc(%si) cmp 0x8(%si),%ax jge 0x00000161 mov 0xd(%si),%dl shl $0x6,%dl mov 0xa(%si),%cl inc %cl or %dl,%cl mov 0xc(%si),%ch pop %dx mov 0xb(%si),%dh mov $0x7000,%bx mov %bx,%es xor %bx,%bx Dirección .data:0x00007D40 .data:0x00007D43 .data:0x00007D45 .data:0x00007D47 .data:0x00007D49 .data:0x00007D4d .data:0x00007D4e .data:0x00007D4f .data:0x00007D52 .data:0x00007D54 .data:0x00007D56 .data:0x00007D58 Hexadecimal b80102 cd13 722a 8cc3 8e06487c 60 1e b90001 8edb 31f6 31ff fc .data:0x00007D59 f3a5 .data:0x00007D5b .data:0x00007D5c .data:0x00007D5d .data:0x00007D61 .data:0x00007D64 .data:0x00007D67 .data:0x00007D69 .data:0x00007D6c .data:0x00007D6f .data:0x00007D71 .data:0x00007D74 .data:0x00007D77 .data:0x00007D7a .data:0x00007D7d .data:0x00007Da0 .data:0x00007Da3 .data:0x00007Da5 .data:0x00007Da7 .data:0x00007Da8 .data:0x00007Daa .data:0x00007Dac .data:0x00007Dc3 .data:0x00007Dc6 .data:0x00007Dc8 .data:0x00007Dca .data:0x00007Dcb .data:0x00007Dcd .data:0x00007Dd0 .data:0x00007Dd2 1f 61 ff26427c be857d e84000 eb0e be8a7d e83800 eb06 be947d e83000 be997d e82a00 ebfe bb0100 b40e cd10 ac 3c00 75f4 c3 bebd7d 31c0 cd13 46 8a0c 80f900 750f beda7d 113 Ensamblador mov $0x201,%ax int $0x13 jb 0x00000171 mov %es,%bx mov 0x7c48,%es pusha push %ds mov $0x100,%cx mov %bx,%ds xor %si,%si xor %di,%di cld rep movsw %ds:(%si),%es:(%di) pop %ds popa jmp *0x7c42 mov $0x7d85,%si call 0x000001a7 jmp 0x00000177 mov $0x7d8a,%si call 0x000001a7 jmp 0x00000177 mov $0x7d94,%si call 0x000001a7 mov $0x7d99,%si call 0x000001a7 jmp 0x0000017d mov $0x1,%bx mov $0xe,%ah int $0x10 lods %ds:(%si),%al cmp $0x0,%al jne 0x000001a0 ret mov $0x7dbd,%si xor %ax,%ax int $0x13 inc %si mov (%si),%cl cmp $0x0,%cl jne 0x000001e1 mov $0x7dda,%si Dirección .data:0x00007Dd5 .data:0x00007Dd8 .data:0x00007De1 .data:0x00007De4 .data:0x00007De7 .data:0x00007De9 .data:0x00007Deb .data:0x00007Ded .data:0x00007Def .data:0x00007Df1 .data:0x00007Df3 Hexadecimal e8cfff eb9d bb0070 b80102 b500 b600 cd13 72d7 b601 b54f e9e6fe Ensamblador call 0x000001a7 jmp 0x00000177 mov $0x7000,%bx mov $0x201,%ax mov $0x0,%ch mov $0x0,%dh int $0x13 jb 0x000001c6 mov $0x1,%dh mov $0x4f,%ch jmp 0x00007cdc Tabla 23. Codigo NTLDR. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Nota: Para saber que partes del código hexadecimal fueron eliminadas, se puede seguir la columna de dirección, este código hexadecimal representa parámetros del gestor de arranque. Para estudiar el código libre de grub se unirá el archivo de cabecera stage1.h y el código stage1.S en uno solo stage1Total. Unión de los archivos de Primera Etapa. Para Unir los archivos de la primera etapa que se crearon por la construcción de GRUB se utilizara la herramienta de Linux gcc así: 1. Se tiene que abrir una terminal y por medio del uso del comando cd de Linux y una ruta absoluta se procede a colocar en el directorio de stage1. Figura 43. Ingreso a Directorio stage1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 114 2. Ejecutamos el comando grub colocando argumentos que detengan el proceso en momento de ensamblaje. Así como el código de la primera etapa esta en código ensamblador. El comando gcc pre procesara los archivos uniéndoles, compilara el archivo en este paso la compilación lo que hará es eliminar comentarios y los parámetros definidos en la cabecera serán colocados en cualquier parte que el archivo stage1.S lo tenga registrado, y tratara de ensamblar el archivo en el ensamblaje no se realizara ningún proceso ya que el código que se le paso es lenguaje ensamblador logrando así el objetivo de tener un solo archivo con el que se pueda estudiar el código más fácilmente. Figura 44. Creación de archivo total fuente stage1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Como se verifica en la figura anterior se crea un archivo denominado stage1Total, al ejecutar el comando: # gcc -S stage1.S -I /root/Downloads/grub-0.97/ > stage1Total El archivo stage1Total contiene el siguiente código ensamblador: .file "stage1.S" .text .code16 .globl _start; _start: jmp after_BPB nop . = _start + 4 115 mode: .byte 0 disk_address_packet: sectors:.long 0 heads: .long 0 cylinders: .word 0 sector_start: .byte 0 head_start: .byte 0 cylinder_start: .word 0 . = _start + 0x3e stage1_version: .byte 3, 2 boot_drive: .byte 0xFF force_lba: .byte 0 stage2_address: .word 0x8000 stage2_sector: .long 1 stage2_segment: .word 0x800 after_BPB: cli boot_drive_check: jmp 1f testb $0x80, %dl jnz 1f movb $0x80, %dl 1: ljmp $0, $(real_start-_start+0x7c00) real_start: xorw %ax, %ax movw %ax, %ds movw %ax, %ss movw $0x2000, %sp sti .byte 0xa0; .word (boot_drive-_start+0x7c00) cmpb $0xFF, %al je 1f movb %al, %dl 1: pushw %dx movw $(notification_string-_start+0x7c00), %si; call message testb $0x80, %dl jz chs_mode movb $0x41, %ah movw $0x55aa, %bx int $0x13 popw %dx pushw %dx jc chs_mode cmpw $0xaa55, %bx 116 jne chs_mode .byte 0xa0; .word (force_lba-_start+0x7c00) testb %al, %al jnz lba_mode andw $1, %cx jz chs_mode lba_mode: movl 0x10(%si), %ecx movw $(disk_address_packet-_start+0x7c00), %si movb $1, -1(%si) movl (stage2_sector-_start+0x7c00), %ebx movw $0x0010, (%si) movw $1, 2(%si) movl %ebx, 8(%si) movw $0x7000, 6(%si) xorl %eax, %eax movw %ax, 4(%si) movl %eax, 12(%si) movb $0x42, %ah int $0x13 jc chs_mode movw $0x7000, %bx jmp copy_buffer chs_mode: movb $8, %ah int $0x13 jnc final_init testb $0x80, %dl jz floppy_probe jmp hd_probe_error final_init: movw $(sectors-_start+0x7c00), %si movb $0, -1(%si) xorl %eax, %eax movb %dh, %al incw %ax movl %eax, 4(%si) xorw %dx, %dx movb %cl, %dl shlw $2, %dx movb %ch, %al movb %dh, %ah incw %ax movw %ax, 8(%si) xorw %ax, %ax movb %dl, %al 117 shrb $2, %al movl %eax, (%si) setup_sectors: movl (stage2_sector-_start+0x7c00), %eax xorl %edx, %edx divl (%si) movb %dl, 10(%si) xorl %edx, %edx divl 4(%si) movb %dl, 11(%si) movw %ax, 12(%si) cmpw 8(%si), %ax jge geometry_error movb 13(%si), %dl shlb $6, %dl movb 10(%si), %cl incb %cl orb %dl, %cl movb 12(%si), %ch popw %dx movb 11(%si), %dh movw $0x7000, %bx movw %bx, %es xorw %bx, %bx movw $0x0201, %ax int $0x13 jc read_error movw %es, %bx copy_buffer: movw (stage2_segment-_start+0x7c00), %es pusha pushw %ds movw $0x100, %cx movw %bx, %ds xorw %si, %si xorw %di, %di cld rep movsw popw %ds popa jmp *(stage2_address) geometry_error: movw $(geometry_error_string-_start+0x7c00), %si; call message jmp general_error hd_probe_error: movw $(hd_probe_error_string-_start+0x7c00), %si; 118 call message jmp general_error read_error: movw $(read_error_string-_start+0x7c00), %si; call message general_error: movw $(general_error_string-_start+0x7c00), %si; call message stop: jmp stop notification_string: .string "GRUB " geometry_error_string: .string "Geom" hd_probe_error_string: .string "Hard Disk" read_error_string: .string "Read" general_error_string: .string " Error" 1: movw $0x0001, %bx movb $0xe, %ah int $0x10 message: lodsb cmpb $0, %al jne 1b ret . = _start + 0x1b8 nt_magic: .long 0 .word 0 part_start: . = _start + 0x1be probe_values: .byte 36, 18, 15, 9, 0 floppy_probe: movw $(probe_values-1 -_start+0x7c00), %si probe_loop: xorw %ax, %ax int $0x13 incw %si movb (%si), %cl cmpb $0, %cl jne 1f movw $(fd_probe_error_string-_start+0x7c00), %si; call message jmp general_error fd_probe_error_string: .string "Floppy" 1: movw $0x7000, %bx movw $0x201, %ax 119 movb $0, %ch movb $0, %dh int $0x13 jc probe_loop movb $1, %dh movb $79, %ch jmp final_init . = _start + 0x1fe .word 0xaa55 Código stage1Total Estructura del Código Examinando el código libre de GRUB en el directorio stage1, y el código que se genera de la aplicación de herramienta de ingeniería inversa podemos estructurar el código hexadecimal de la siguiente manera: Figura 45. Código hexadecimal diferenciado de GRUB Primera Etapa. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 120 Al Código de GRUB lo podemos estructurar en tres partes principales: La sección de código que se muestra en amarillo. La sección de mensajes mostrada en verde. La sección firma mostrada en rojo. La sección de parámetros mostrada en los demás colores excepto el blanco. Nota: la sección de blanco en código no se utiliza es necesaria para dar formato a la posición del código. El código libre que se unió y el código que se obtuvo de la ingeniería inversa se procederán a estudiar teniendo en cuenta la estructura antes indicada. Se dividirá la sección de código según sea necesario para diferenciar partes como funciones, saltos de código que leen parámetros de configuración, cambian parámetros, y como la primera etapa del código carga la segunda etapa. 3.5.7 .1 Primera parte del Código Figura 46. Código Hexadecimal GRUB parte 1 Autor: Tesista. Fuente: Desarrollo de tema de tesis. Código Comentario .file "stage1.S" /*Indica el nombre del archivo*/ /*Directiva de gas que indica la sección de código*/ .text .code16 .globl _start; _start: jmp after_BPB nop /*Directiva que indica que el código debe ser generado como de 16 bits*/ /*Directiva que indica el inicio del código.*/ /*Etiqueta de inicio del código*/ /*Salta a la etiqueta BPB(BIOS parámetros bloque)*/ /*Instrucción nula*/ Tabla 24. Codigo GRUB parte 1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 121 Dirección Hexadecimal .data:0x00007C00 eb48 .data:0x00007C02 90 Ensamblador Comentario /*Salta a la d122irección jmp 0x00007c4a 0:07c4a*/ nop /*Instrucción nula*/ Tabla 25. Código GRUB desensamblado parte 1. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La primera secion del código toma los primeros 3 bytes, su función es saltar la sección de condifiguracion de parámetro de bloque de BIOS y demás parámetros de configuración. En este caso salta a la posición de memoria 0:07c4a que es donde inicia la cuarta parte del código. 3.5.7 .2 Segunda parte del Código Figura 47. Código Hexadecimal GRUB parte 2. Autor: Tesista. Fuente: Desarrollo de tema de tesis. Color Hexadecimal Código Comentario /*Salta 4 bytes desde el inicio*/ . = _start + 4 /*Asigna el valor de 0 al byte en la quinta posición del código, representa el mode*/ mode: .byte 0 disk_address_packet: /*Etiqueta, indica el inicio del bloque del direccionamiento del disco. */ sectors: .long 0 /*Almacena en 4 bytes el numero de sectores*/ heads: .long 0 /*Almacena en 4 bytes el numero de cabeceras*/ cylinders: .word 0 /*Almacena en una palabra o dos bytes el numero de cilindros*/ /*Etiqueta indica el bloque del sector de inicio.*/ /*Alamacena en un byte el valor 0*/ sector_start: .byte 0 122 Color Hexadecimal Código Comentario /*Etiqueta indica el bloque de la cabecera de inicio.*/ /*Alamacena en un byte el valor 0*/ head_start: .byte 0 /*Etiqueta indica el bloque de el cilindro de inicio.*/ cylinder_start: /*Almacena en una palabra dos bytes el valor 0 */ .word 0 /*Salta al byte 0x3e, al byte 62 en decimal*/ . = _start + 0x3e Tabla 26. Código GRUB parte 2. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La segunda parte del código su objetivo es crear posiciones en memoria de la estructura del disco, como son el numero de sectores, el numero de cabeceras, el sector de inicio. En el código existen etiquetas estas no ocupan ningún esapcio en el código binario ya que sirven para dar mecanismo al código, saltos, bucles, etc. En esta parte de código existe el nemotécnico .=_start+nn, esta significa que desde el inicio del código almacenara valores nulos n veces, el objetivo es estructurar el código. Los parámetros que se crean en esta parte del código sus valores son reescritos al ejecutarse las demás prociones del código. Este bloque es conocido como el bloque de parameros del BIOS. 3.5.7.3 Tercera parte del Código Figura 48. Código Hexadecimal GRUB parte 2. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 123 Color Hexadecimal Código Comentario stage1_version: /*Etiqueta que identifica la versión */ .byte 3, 2 /*Almacena doy bytes con valor 3 y 2 son la versiones*/ boot_drive: .byte 0xFF /*Etiqueta que identifica el controlador de inicio*/ /*Almacena el byte 0xFF*/ force_lba: .byte 0 /*Etiqueta que indica si el dispositivo acepta lba*/ /*Almacena el valor cero como byte*/ stage2_address: /*Etiqueta que inidica la posion en la iniciara la etapa 2*/ .word 0x8000 /*Alamacena el valor 0x800 como palabra*/ stage2_sector: /*Etiqueta que indica el numero de sectores de la etapa 2*/ .long 1 /*Almacena el valor 1 en cuatro bytes*/ stage2_segment: /*Etiqueta que inidica el segmento de etapa 2*/ .word 0x800 /*Alamacena el valor 0x800 en dos bytes o como palabra.*/ Tabla 27. Código GRUB Parte 3. Autor: Tesista. Fuente: Desarrollo de tema de tesis. En la tercera etapa del código se configuran parámetros de la primera y segunda etapa de GRUB, como la versión de GRUB, si soporta lba, el sector de inicio de la segunda etapa, el tamaño de la segunda epata en sectores etc. Algunos de estos valores cambian conforme se ejecuta el código. 3.5.7.4 Cuarta parte del Código Para el estudio de la cuarta parte del código se unira el código desensamblado y el código libre de GRUB, se comentara las líneas del programa. 124 Código Dirección Nemotécnico Desensamblado Código Libre 0x7C4a 0x7C4b Fa eb07 cli jmp 0x00007c54 Comentario after_BPB: /*Etiqueta que indica el fin del Bloque BPB*/ cli /*Establece en cero las banderas de interrupción. Desabilitando las interrupciones enmascarables*/ boot_drive_check: /*Etiqueta que indica el Bloque donde se puede comparar el controlador de inicio*/ jmp 1f /*Salta a la etiqueta 1:, Actualmente en la posición 0x7c54*/ 0x7C4d f6c280 test $0x80,%dl testb $0x80, %dl /*Realiza una operación and entre el valor 0x80 y dl, las BIOS antes de dar el control al mbr almacenan valores de configuración por ejemplo colocan el controlador del dispositivo de donde van a arrancar en dl*/ 0x7C50 7502 jne 0x00007c54 jnz 1f /*Salta a la etiqueta 1 o dirección 0:07c54, si dl no tiene el 0x80*/ 0x7C52 b280 mov $0x80,%dl movb $0x80, %dl /*Mueve el valor 0x80 a dl*/ 1: /*Etiqueta de código*/ ljmp $0, $(real_start_start+0x7c00) /*Salta a la posicionde memoria cs,ip, en este caso 0:07c59*/ real_start: /*Etiqueta de código, su valor lo calcula el compilador pero solo para estructurar el código.*/ 0x7C54 ea597c0000 ljmp $0x0,$0x7c59 125 Código Dirección Nemotécnico Desensamblado Código Libre Comentario 0x7C59 31c0 xor %ax,%ax xorw %ax, %ax /*Establece en ax =0*/ 0x7C5b 8ed8 mov %ax,%ds movw %ax, %ds /*Mueve el valor de ax a ds, Establece ds=0*/ 0x7C5d 8ed0 mov %ax,%ss movw %ax, %ss /*Mueve el valor de ax a ss, Establece ss=0*/ 0x7C5f bc0020 mov $0x2000,%sp movw $0x2000, %sp /*Establece en sp el numero 0x2000*/ 0x7C62 Fb sti sti /*Activa las banderas de interrupción*/ 0x7C63 a0407c .byte 0xa0; .word mov 0x7c40,%al (boot_drive_start+0x7c00) /*Mueve el valor de la dirección 0:0x7C40 a al, es el valor de boot_drive actualmente 0xff*/ 0x7C66 3cff cmp $0xff,%al cmpb $0xFF, %al /*Realiza una comparación 0xFF con al*/ 0x7C68 7402 je 0x00007c6c je 1f /*Si en la comparación anterior sus valore eran iguales salta a la proxima etiqueta 1:, o lo que es lo mismo a la dirección 0x7C6C*/ 0x7C6a 88c2 mov %al,%dl movb %al, %dl /*Mueve el contenido del registro al a dl*/ 1: /*Etiqueta del código*/ push %dx pushw %dx /*Apila el valor de dx*/ mov $0x7d7f,%si movw $(notification_string_start+0x7c00), %si; /*Mueve el valor de de la dirección en que inicia notification_ string a si, Se prepara para imprimir un mensaje*/ 0x7C6c 0x7C6d 0x7C70 52 be7f7d e83401 call 0x00007da7 call message 126 /*llama a la función message, que inicia en la dirección 0:07da7*/ Código Dirección Nemotécnico Desensamblado Código Libre 0x7C73 f6c280 test $0x80,%dl Comentario testb $0x80, %dl /*Realiza una operación and de el valor de 0x80 con dl*/ 0x7C76 7454 je 0x00007ccc jz chs_mode /*Si la operación test o and anterior dio igula a cero salta a la etiqueta chs_mode o 0:07ccc. Para ver la estructara del disco en la especificacion chs*/ 0x7C78 b441 mov $0x41,%ah movb $0x41, %ah /*Establece el valor de ox41h a ah, Es para comprobar si soprta lba*/ 0x7C7a bbaa55 mov $0x55aa,%bx movw $0x55aa, %bx /*Parametro de la int 13h*/ 0x7C7d cd13 int $0x13 int $0x13 /*Ejecuta la int 13h CF Activada en error (no hay extensiones) AH = Número de la versión mayor de las extensiones BX = 55AAh Devuelve 55AAh si están instaladas CX = bits de las extensiones instaladas (Bit 0-15) DH = Versión de las extensiones*/ 0x7C7f 0x7C80 5ª 52 pop %dx push %dx popw %dx pushw %dx /*Apila dx*/ /*Des apila dx*/ 0x7C81 7249 jb 0x00007ccc jc chs_mode /*Si la anterio int 13h activo cf no acepta lba y salta a la etiqueta chs_mode*/ 0x7C83 81fb55aa cmp $0xaa55,%bx cmpw $0xaa55, %bx /*Compara la palabra 0xaa55 con bx, para verificar que soporta lba*/ jne chs_mode /*En caso de no soportar lba salta a la etiqueta chs_mode*/ 0x7C87 7543 jne 0x00007ccc 127 Código Dirección Nemotécnico Desensamblado Código Libre Comentario 0x7C89 a0417c .byte 0xa0; .word mov 0x7c41,%al (force_lba_start+0x7c00) 0x7C8c 84c0 test %al,%al testb %al, %al /*Realiza una comparación and para verificar si al es cero*/ 0x7C8e 7505 jne 0x00007c95 jnz lba_mode /*Si al no es cero sal ta a la etiqueta lba_mode*/ and $0x1,%cx andw $1, %cx /*Realiza una operación and entre el valor 1 y cx, Actualmente cx contiene bits de las extensiones instaladas*/ jz chs_mode /*Si la operación and dio cero salta a la etiqueta chs_mode*/ 0x7C90 0x7C93 83E103 7437 je 0x00007ccc /*Mueve el valor de la direccion0:07c41 a al. Etiqueta de lba*/ Tabla 28. Código GRUB parte 4. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La cuarta parte del código lo que realiza es crear una pila establecer los valores de segementos de datos, segmento extra etc. Imprime un mensaje. Verifica si la BIOS soporta el equema lba de ser así salta a la quinta parte del código en la que se revisa los parámetros de lba, caso sontrario salta a la sexta parte del código donde se revisa el esquema chs. 3.5.7.5 Quinta parte del Código Código Dirección Nemotécnico Desensamblado Código Libre lba_mode: 128 Comentario /*Etiqueta de código, Indica el inicio del bloque de la especificacion lba*/ Código Dirección Nemotécnico 0x7C95 0x7C99 0x7C9c 0x7Ca0 0x7Ca5 0x7Ca9 668b4c10 be057c c644ff01 668b1e447c c7041000 c744020100 Desensamblado Código Libre Comentario /*Mueve 4 bytes de la dirección 0:si+16 a ecx, Puede mover 4 bytes si se este menejando modo real*/ mov 0x10(%si),%ecx movl 0x10(%si), %ecx mov $0x7c05,%si movw $(disk_address_packet_start+0x7c00), %si /*Mueve la dirección de disk_adress_packet a si*/ movb $1, -1(%si) /*Mueve el valor de 1 un byte antes de la dirección que almacena si, Este valor representa el modo*/ movl (stage2_sector_start+0x7c00), %ebx /*Mueve la dirección de stage2_sector_start a ebx, el valor de 1*/ movw $0x0010, (%si) /*Establece el valor 0x0010 a la dirección que apunta si, si apunta a disk_adress_packet quedando en memoria 10 00, el tamaño del dap es de 0x10 */ movw $1, 2(%si) /*Establece el valor de 0x0001 a los 2 bytes siguiente que apunta si, quedando el dap 10 00 01 00*/ movb $0x1,0x1(%si) mov 0x7c44,%ebx movw $0x10,(%si) movw $0x1,0x2(%si) 129 Código Dirección Nemotécnico Desensamblado Código Libre 0x7Cae 66895c08 mov %ebx,0x8(%si) movl %ebx, 8(%si) 0x7Cb2 c744060070 movw $0x7000,0x6(%si) movw $0x7000, 6(%si) 0x7Cb7 6631c0 xor %eax,%eax xorl %eax, %eax 0x7Cba 894404 mov %ax,0x4(%si) movw %ax, 4(%si) 0x7Cbd 6689440c mov %eax,0xc(%si) movl %eax, 12(%si) 130 Comentario /*Mueve el valor de ebx actualmente 1 a la dirección que apunta el registro si mas 8 bytes. Absoluto numero de inicio de los sectores a ser leido.Quedando dap 10 00 01 00 ?? ?? ?? ?? 01 00 00 00*/ /*Mueve la palabra 0x7000 a la dirección apuntada por si +6 bytes reprensenta la dirección de memoria donce se lamacenarn los sectores leidos. Quedando dap 10 00 01 00 ?? ?? 00 70 01 00 00 00 00*/ /*Establece eax=0*/ /*Mueve el valor de ax=0 a la dirección que apunta si, para completar el numero de sectores leidos, quedando el dap así: 10 00 01 00 00 00 00 70 01 00 00 00 00*/ /*Mueve el valor de eax a la dirección que apunta si + 12 bytes, Paa completar el dap.*/ Código Dirección Nemotécnico Desensamblado Código Libre 0x7Cc1 b442 mov $0x42,%ah movb $0x42, %ah 0x7Cc3 cd13 int $0x13 int $0x13 0x7Cc5 7205 jb 0x00007ccc jc chs_mode 0x7Cc7 bb0070 mov $0x7000,%bx movw $0x7000, %bx 0x7Cca eb7d jmp 0x00007D49 jmp copy_buffer Comentario /*Establece el valor de 0x42h a ah*/ /*Ejecuta la int 13h con función 42 h, para ller los sectores del disco según los parámetros de dl y si, Si hay error ctiva cf*/ /*En caso de la int13h ejecutar error salta a la etiqueta chs_mode*/ /*Establece le valor de 0x7000 a bx*/ /*Salta a a copiar el buffer, o a la dirección 0:7D49*/ Tabla 29. Código GRUB parte 5. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La quinta parte del código configura los parámetros de la especificación lba, y lee del disco el sector de la segunda etapa La información leída del disco la almacena en memoria, para en la quinta parte del código volver a copiarla a otro lado de memoria. Sexta parte del Código Código Dirección Nemotécnico 0x7Ccc b408 Desensamblado mov $0x8,%ah Código Libre Comentario chs_mode: /*Etiqueta de código*/ movb $8, %ah /*Establece el valor de 0x8 a ah. Función 8h*/ 131 Código Dirección Nemotécnico Desensamblado Código Libre 0x7Cce cd13 int $0x13 int $0x13 0x7Cd0 730ª jae 0x00007cdc jnc final_init 0x7Cd2 f6c280 test $0x80,%dl testb $0x80, %dl 0x7Cd5 0f84ea00 je 0x00007dc3 jz floppy_probe 0x7Cd9 e98d00 jmp 0x00007d69 jmp hd_probe_error final_init: 0x7Cdc be057c mov $0x7c05,%si movw $(sectors_start+0x7c00), %si 0x7Cdf c644ff00 movb $0x0,0x1(%si) movb $0, -1(%si) 0x7Ce3 6631c0 xor %eax,%eax xorl %eax, %eax 132 Comentario /*Ejecuta la interrupción 13 función 8h , para obtener los parámetros del disco*/ /*Se la lectura de los parámetros no da error salta a final_init o a la dirección 0:07cdc*/ /*Realiza una operación and bit a bit del valor 0x80 con dl*/ /*Si la operación and dio cero salta a la etiqueta floppy_probe cuya dirección es 0:7dc3*/ /*Salta a ejecutar un mensaje de error a la dirección 0:7d69*/ /*Etiqueta de código*/ /*Mueve el valor de la dirección de la etiqueta sector a si. En este caso 0x7c05*/ /*Establece el valor de cero a la dirección que apunta si menos un byte, en este caso es el mode*/ /*Establece eax=0*/ Código Dirección Nemotécnico Desensamblado Código Libre Comentario /*Mueve el valor de dh a al, dh es una valor almacenado por la BIOS antes de dar el control al MBR*/ 0x7Ce6 88f0 mov %dh,%al movb %dh, %al 0x7Ce8 40 inc %ax incw %ax 0x7Ce9 66894404 mov %eax,0x4(%si) movl %eax, 4(%si) 0x7Ced 31d2 xor %dx,%dx xorw %dx, %dx /*Establece dx=0*/ 0x7Cef 88ca mov %cl,%dl movb %cl, %dl /*Mueve el valor de cl a dl*/ 0x7Cf1 c1e202 shl $0x2,%dx shlw $2, %dx 0x7Cf4 8800000000 mov %ch,%al movb %ch, %al 0x7Cf6 88f4 mov %dh,%ah movb %dh, %ah /*Mueve el valor de dh a ah*/ 0x7Cf8 40 inc %ax incw %ax 0x7Cf9 894408 mov %ax,0x8(%si) movw %ax, 8(%si) 0x7Cfc 31c0 xor %ax,%ax xorw %ax, %ax /*Incrementa ax en una unidad*/ /*Mueve el valor de ax a la dirección de si + 8 bytes. Representa el número de cilindros */ /*Establece ax=0*/ 0x7Cfe 88d0 mov %dl,%al movb %dl, %al 0x7D00 c0e802 shr $0x2,%al shrb $2, %al 133 /*Incrementa en una unidad el valor de ax*/ /*Mueve el valor de eax a la dirección que apunta si + 4 bytes, el número de cabeceras*/ /*Desplaza 2 bits a la izquierda el valor de dx*/ /*Mueve ch a al*/ /*Mueve el valor de dl a al*/ /*Recorre 2 bits a a la derecha el valor de al*/ Código Dirección Nemotécnico 0x7D03 668904 Desensamblado mov %eax,(%si) Código Libre movl %eax, (%si) setup_sectors: 0x7D06 66a1447c mov 0x7c44,%eax movl (stage2_sector_start+0x7c00), %eax 0x7D0a 6631d2 xor %edx,%edx xorl %edx, %edx 0x7D0d 66f734 divl (%si) divl (%si) 0x7D10 88540ª mov %dl,0xa(%si) movb %dl, 10(%si) 0x7D13 6631d2 xor %edx,%edx xorl %edx, %edx 0x7D16 66f77404 divl 0x4(%si) divl 4(%si) 0x7D1a 88540b mov %dl,0xb(%si) movb %dl, 11(%si) 134 Comentario /*Mueve el valor de eax a la dirección que almacena si. Representa el número de sectores*/ /*Etiqueta de Código*/ /*Mueve la dirección que contiene la etiqueta stage2_sector a eax, en este caso 0x7c44*/ /*Establece edx=0*/ /*Divide el valor de eax para el valor que almacena la dirección de si*/ /*Mueve el valor de dl a la dirección de memoria si +10 bytes. Representa el sector de inicio de la segunda etapa*/ /*Establece edx=0*/ /*Divide el valor de eax para el valor que almacena la dirección de si + 4 bytes*/ /*Mueve el valor de dl a la dirección de si +11 bytes*/ Código Dirección Nemotécnico Desensamblado Código Libre Comentario /*Mueve el valor de ax a la dirección de si +12 bytes*/ /*Realiza una comparación entre el valor de la dirección de si +8 bytes y el registro dl */ 0x7D1d 89440c mov %ax,0xc(%si) movw %ax, 12(%si) 0x7D20 3b4408 cmp 0x8(%si),%ax cmpw 8(%si), %ax 0x7D23 7d3c jge 0x00007d61 jge geometry_error 0x7D25 8a540d mov 0xd(%si),%dl movb 13(%si), %dl 0x7D28 c0e206 shl $0x6,%dl shlb $6, %dl /*Recorre 6 bits a la izquierda del registro dl*/ 0x7D2b 8a4c0a mov 0xa(%si),%cl movb 10(%si), %cl /*Mueve el valor de la dirección de si +10 bytes a cl*/ 0x7D2e fec1 inc %cl incb %cl 0x7D30 08d1 or %dl,%cl orb %dl, %cl 0x7D32 8a6c0c mov 0xc(%si),%ch movb 12(%si), %ch 0x7D35 5ª pop %dx popw %dx 0x7D36 8a740b mov 0xb(%si),%dh movb 11(%si), %dh 0x7D39 bb0070 mov $0x7000,%bx movw $0x7000, %bx 135 /*Salta a la dirección 0:07d61 si existe error*/ /*Mueve el valor de la dirección de si + 14 bytes a dl*/ /*Incrementa el valor de cl*/ /*Realiza la operación or entre dl y cl almacenado el resultado en cl, suma dl , cl*/ /*Mueve el valor de la dirección de si +12 bytes a ch*/ /*des apila dx*/ /*Mueve el valor de la dirección de si +11 bytes a dh*/ /*Mueve el valor de 0x7000 a bx*/ Código Dirección Nemotécnico Desensamblado Código Libre Comentario 0x7D3c 8ec3 mov %bx,%es movw %bx, %es /*Mueve el valor de bx a es*/ 0x7D3e 31db xor %bx,%bx xorw %bx, %bx /*Establece el valor de bx =0*/ 0x7D40 b80102 mov $0x201,%ax movw $0x0201, %ax 0x7D43 cd13 int $0x13 int $0x13 0x7D45 722ª jb 0x00000171 jc read_error 0x7D47 8cc3 mov %es,%bx movw %es, %bx /*Establece los parámetros de la función ah=02, al =01 de la int13h*/ /*Ejecuta la int 13h para leer los sectores de la etapa 2 con los valores antes configurados*/ /*Si la lectura da error salta a la etiqueta read_error que es la dirección 0:7d71*/ /*Muestra el valor de es a bx*/ Tabla 30. Código GRUB parte 6. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La sexta parte del código configura los parámetros de la especificación chs y verifica que todo este normal caso contrario salta a imprimir mensajes de error. Carga a memoria el sector de segunda etapa igual que la quinta parte solo que en esta ocasión con la especificación chs. Continúa con la séptima parte del código. 136 Séptima parte del Código Código Dirección Nemotécnico 0x7D49 8e06487c 0x7D4d 0x7D4e 60 1e 0x7D4f b90001 Desensamblado Código Libre mov 0x7c48,%es movw (stage2_segment_start+0x7c00), %es pusha push %ds pusha pushw %ds mov $0x100,%cx movw $0x100, %cx 0x7D52 8edb mov %bx,%ds movw %bx, %ds 0x7D54 0x7D56 31f6 31ff xor %si,%si xor %di,%di xorw %si, %si xorw %di, %di 0x7D58 Fc cld cld 0x7D59 f3a5 rep movsw %ds:(%si),%es:(%di) rep movsw Comentario /*Mueve el valor en palabra o dos bytes del que apunta la dirección stage2_segment_start a es. En este caso 0x80 00*/ /*Apila ax*/ /*Apila ds*/ /*Establece el valor de 0x100 a cx*/ /*Mueve el valor de bx a ds, bx almacenaba 0x7000*/ /*Establece si =0*/ /*Establece di=0*/ /*Limpia la bandera de dirección*/ /*Repite cx veces e movimiento de la palabra de ds:si a es:di, en esta ocasión cx=256. Es decir mueve el bloque que leyó del disco y los traslada a la dirección 80000:0*/ Tabla 31. Código GRUB parte 7. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La séptima parte del código lo que realiza es copiar 512 bytes desde la posición de memoria 7000:000 a la dirección de memoria 8000:000. 137 Octava parte del Código Código Dirección Nemotécnico Desensamblado Código Libre Comentario /*Des apila ds establece ds=0*/ 0x7D5b 1f pop %ds popw %ds 0x7D5c 61 popa popa 0x7D5d ff26427c jmp *0x7c42 jmp *(stage2_address) /*Des apila ax, Establece ax=0*/ /*Salta a la dirección contenida en la dirección de stage2_adress , en este caso 0x8000,. Aquí termina etapa 1 pasa a la etapa 2*/ Tabla 32. Código GRUB parte 8. Autor: Tesista. Fuente: Desarrollo de tema de tesis. La octava parte del código realiza la limpieza del registro de datos y del acumulador. Salta a la dirección 0x8000:0x000 que es el inicio del código de la segunda etapa Novena parte del código Código Dirección Nemotécnico Desensamblado Código Libre geometry_error: 0x7D61 0x7D64 be857d e84000 mov $0x7d85,%si Comentario /*Etiqueta de código*/ /*Mueve el valor de la dirección de la etiqueta movw geometry_error_string $(geometry_error_stringa si. Se prepara para _start+0x7c00), %si; imprimir mensaje de error*/ call 0x000001a7 call message 138 /*Llama a la función message para imprimir mensaje de error*/ Código Dirección Nemotécnico Desensamblado 0x7D67 eb0e jmp 0x00000177 0x7D69 be8a7d mov $0x7d8a,%si 0x7D6c e83800 call 0x000001a7 0x7D6f eb06 jmp 0x00000177 0x7D71 be947d mov $0x7d94,%si 0x7D74 e83000 call 0x000001a7 Código Libre Comentario jmp general_error /*Salta a la dirección de la etiqueta general error para imprimir el mensaje de error general*/ hd_probe_error: /*Etiqueta de código*/ /*Mueve el valor de la dirección de la etiqueta movw hd_probe_error_string $(hd_probe_error_stringa si. Se prepara para _start+0x7c00), %si; imprimir mensaje de error*/ call message /*Llama a la función message para imprimir mensaje de error*/ jmp general_error /*Salta a la dirección de la etiqueta general error para imprimir el mensaje de error general*/ read_error: /*Etiqueta de código*/ movw $(read_error_string_start+0x7c00), %si; /*Mueve el valor de la dirección de la etiqueta read_error_string a si. Se prepara para imprimir mensaje de error*/ call message /*Llama a la función message para imprimir mensaje de error*/ general_error: /*Etiqueta de código*/ 139 Código Dirección Nemotécnico Desensamblado 0x7D77 0x7D7a 0x7D7d be997d e82a00 Ebfe mov $0x7d99,%si Código Libre Comentario movw $(general_error_string_start+0x7c00), %si; /*Mueve el valor de la dirección de la etiqueta general_error_string a si. Se prepara para imprimir mensaje de error*/ call message /*Llama a la función message para imprimir el mensaje de error*/ stop: /*Etiqueta de código*/ jmp stop /*Salta a la etiqueta de código stop. Crea un bucle infinito*/ call 0x00007da7 jmp 0x00007d7d /*Etiqueta de código notification_string: .string que representa el inicio "GRUB " de la cadena GRUB*/ geometry_error_string: .string "Geom" /*Etiqueta de código que representa el inicio de la cadena Geom*/ hd_probe_error_string: .string "Hard Disk" /*Etiqueta de código que representa el inicio de la cadena Hard Disk*/ /*Etiqueta de código read_error_string: .string que representa el inicio "Read" de la cadena GRUB*/ general_error_string: .string " Error" /*Etiqueta de código que representa el inicio de la cadena Error*/ /**/ 0x7D7d Ebfe jmp 0x0000017d 1: 140 /*Etiqueta de código*/ Código Dirección Nemotécnico Desensamblado 0x7Da0 0x7Da3 0x7Da5 0x7Da7 0x7Da8 0x7Daa 0x7Dac bb0100 b40e cd10 Ac 3c00 75f4 c3 mov $0x1,%bx mov $0xe,%ah Código Libre Comentario movw $0x0001, %bx /*Establece el valor de 1 a bx, sirve para el modo grafico específicamente pagina 1*/ movb $0xe, %ah /*Establece el valor de 0xe a ah, es la función de imprimir un carácter*/ int $0x10 /*Ejecuta la interrupción 10h función 0xe, Imprimir carácter*/ message: /*Etiqueta que indica el inicio de la función message*/ lodsb /*Almacena el valor de ds:si a al*/ cmpb $0, %al /*Compara si el valor almacenado en al es cero, esto indica que se alcanzó el fin de la cadena*/ jne 1b /*Si el valor anterior de al no es cero salta a la dirección de memoria 0:7da0*/ ret /*Termino de imprimir la cadena y regresa a la posición de memoria donde fue llamado la función message*/ . = _start + 0x1b8 /*Completa de ceros para que a estructurar el código de la primera etapa de grub*/ int $0x10 lods %ds:(%si),%al cmp $0x0,%al jne 0x00007da0 ret Tabla 33. Código GRUB parte 9. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 141 La novena parte del código contiene etiquetas de mensajes, la función que imprime dichos mensajes, La etiqueta que genera un bucle infinito que es llamada cuando se produce un error. Décima parte del código Código Dirección Nemotécnico Desensamblado Código Libre floppy_probe: 0x7Dc3 bebd7d mov $0x7dbd,%si 31c0 int $0x13 inc %si incw %si /*Incrementa el valor de si*/ 8a0c mov (%si),%cl movb (%si), %cl /*Mueve el valor de la dirección que contiene si a cl*/ 80f900 cmp $0x0,%cl cmpb $0, %cl /*Realiza una comparación del valor de cero con cl*/ 0x7Dca 46 0x7Dcb 0x7Dcd 0x7Dd5 xorw %ax, %ax int $0x13 cd13 0x7Dd2 xor %ax,%ax /*Etiqueta de código*/ /*Establece ax=0*/ /*Ejecuta la interrupción 13h con función 0h para resetear el disco*/ 0x7Dc8 0x7Dd0 /*Etiqueta de código*/ movw $(probe_values-1 /*Establece el valor -_start+0x7c00), %si de 0x7dbd a si*/ probe_loop: 0x7Dc6 Comentario 750f jne 0x00007de1 beda7d /*Mueve el valor de la dirección de movw fd_probe_error_string mov $0x7dda,%si $(fd_probe_error_stringa si. Se prepara para _start+0x7c00), %si; imprimir mensaje de error*/ e8cfff jne 1f /*En caso de no ser iguales salta a la dirección 0x7de1*/ call 0x000001a7 call message 142 /*Llama a la función message para imprimir error*/ Código Dirección Nemotécnico Desensamblado Código Libre 0x7Dd8 jmp 0x00000177 jmp general_error /*Salta a la etiqueta general_error, la dirección es 0x7d77*/ fd_probe_error_string: .string "Floppy" /*Etiqueta de código que representa la cadena Floppy*/ eb9d 1: 0x7De1 bb0070 Comentario /*Etiqueta de código*/ movw $0x7000, %bx /*Mueve el valor 0x7000 a bx*/ mov $0x201,%ax movw $0x201, %ax /*Almacena los valores de configuración de la int 13 h en este caso ah=2, al=1*/ mov $0x7000,%bx 0x7De4 b80102 0x7De7 b500 mov $0x0,%ch movb $0, %ch /*Establece el valor de ch=0. Limpia ch*/ 0x7De9 b600 mov $0x0,%dh movb $0, %dh /*Establece el valor de dh=0, limpia el valor de dh*/ 0x7Deb cd13 int $0x13 int $0x13 /*Ejecuta la int 13h para leer el sector de la segunda parte de GRUB del disco*/ 0x7Ded 72d7 jb 0x000001c6 jc probe_loop /*En caso de dar error salta a la etiqueta probe_loop, cuya dirección es 0x7Dc6*/ 0x7Def b601 mov $0x1,%dh movb $1, %dh /*Mueve el valor de 1 a dh*/ 0x7Df1 b54f mov $0x4f,%ch movb $79, %ch /*Mueve el valor de 79 a ch*/ 0x7Df3 e9e6fe jmp 0x00007cdc jmp final_init /*Salta a la etiqueta 0:7cdc*/ . = _start + 0x1fe /*Completa de ceros los bytes restantes para que mida 510 bytes*/ Tabla 34. Código GRUB parte 10. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 143 La décima parte del código es para verificar si el disco de arranque es un disco floppy. Y completa los 510 bytes. Onceava parte del código Dirección 0x7Dfe Nemotécnico 0x55aa Código Desensamblado Código Libre .word 0xaa55 .word 0xaa55 Comentario /*Firma de Arranque*/ Tabla 35. Firma Código GRUB parte 11. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 3.6 Modificación del Gestor de Arranque GRUB Se puede modificar el código del Gestor de arranque GRUB LEGACY ya que es software libre y está bajo licencia GNU GPL. La modificación del Gestor de Arranque grub se la realizara tanto en la primera etapa como en la segunda etapa. Se modificara sus mensajes de error, sus mensajes de presentación, sus comentarios para que aparezcan en pantalla en lenguaje español. Con las herramientas antes indicadas en la construcción de GRUB LEGACY, procederemos a construir el código de GRUB Modificado. Debido al tamaño en código de los archivos de GRUB, en este documento se presentara los archivos que fueron modificados. 144 3.6.1 Modificación Del Archivo stage1.S Archivo stage1.S /* * SISTEMA : GRUB LEGACY MODIFICADO * MODULO : UNIVERSIDAD CENTRAL DEL ECUADOR * PROCESO : Stage1.S * DESCRIPCIÓN : Código en lenguaje ensamblador de 16 bits que tiene un tamaño exacto de * 512, su función es leer de un dispositivo de la pc la segunda etapa de GRUB, * cargarlo a memoria y cederle el control de la pc. Emitir mensajes de error cuando se * producen. * ANALISTAS : Ing. Mauro Rosas, Ing. Jairo Navarro, Ing. Jorge Morales * PROGRAMADOR : Figueroa Cañar Victor Bolívar * FECHA CREACIÓN, MODIFICACIÓN: 05 de Abril del 2015 * LICENCIA: GNU GPL versión 2 o mayor. */ #include <stage1.h> /* Direcciones Absolutas *Esto permite al ensamblador generar la dirección de memoria sin soporte del linker.*/ #define ABS(x) (x-_start+0x7c00) /*Imprime la cadena de mensaje que se le pase como argumento.*/ #define MSG(x) movw $ABS(x), %si; call message /* Mueve el valor de x a al, lo hace directamente en código hexadecimal ya que los binutils no * lo pueden generar.*/ #define MOV_MEM_TO_AL(x) .byte 0xa0; .word x .file "stage1.S" 145 .text /* Indica a gas que genere código de 16 bits, tal que trabaje en modo real. */ .code16 .globl _start; /*Etiqueta de inicio del código de ejecución*/ _start: jmp after_BPB nop . = _start + 4 /*Bloque de configuración del BIOS Parameter Block, en esquema chs o lba.*/ mode: .byte 0 disk_address_packet: sectors: .long 0 .long 0 heads: cylinders: .word 0 sector_start: .byte 0 head_start: .byte 0 cylinder_start: .word 0 /* Finalizo el BPB (BIOS parameter block). */ . = _start + STAGE1_BPBEND 146 stage1_version: .byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR boot_drive: .byte GRUB_INVALID_DRIVE /* El controlador del disco desde *donde se cargara stage2.*/ force_lba: .byte 0 stage2_address: .word 0x8000 stage2_sector: .long 1 stage2_segment: .word 0x800 after_BPB: /*Configuración general*/ cli /* * En esta fase solo salta a la etiqueta próxima 1: */ boot_drive_check: jmp 1f /* El siguiente bloque nunca es ejecutado*/ testb $0x80, %dl jnz 1f movb $0x80, %dl /*Fin bloque sin ejecutar*/ 147 1: /* * Salta a la dirección de memoria 0000:7C00 + la posición * de la etiqueta real_start. */ ljmp $0, $ABS(real_start) real_start: /* Establece ds y ss desde cero*/ xorw %ax, %ax movw %ax, %ds movw %ax, %ss /* Establece el tamaño de la pila */ movw $STAGE1_STACKSEG, %sp sti /* * Comprueba si se tiene una referencia de disco forzado aquí */ MOV_MEM_TO_AL(ABS(boot_drive)) cmpb $GRUB_INVALID_DRIVE, %al je 1f movb %al, %dl 1: /* Almacena en la pila el controlador referenciado primero*/ pushw %dx /* Imprime una notificación de mensaje en pantalla */ 148 MSG(notification_string) /* No prueba esquema LBA si la unidad es un disquete */ testb $STAGE1_BIOS_HD_FLAG, %dl jz chs_mode /* Prueba si LBA es soportado */ movb $0x41, %ah movw $0x55aa, %bx int $0x13 /* * %dl pudo haber sido reescrito por INT 13, AH=41H. * Esto sucede por ejemplo en la AST BIOS 1.04. * Des apila el valor de dx que se apilo y lo vuelve apilar. * es decir restablece el valor de dl */ popw %dx pushw %dx /*Usa el esquema CHS si falla */ jc chs_mode cmpw $0xaa55, %bx jne chs_mode /* Prueba si LBA es soportado, si force_lba es cero */ MOV_MEM_TO_AL(ABS(force_lba)) testb %al, %al jnz lba_mode andw $1, %cx jz chs_mode 149 lba_mode: /* Guarda el total número de sectores. */ movl 0x10(%si), %ecx /* Establece %si a el dpa (disk address packet) */ movw $ABS(disk_address_packet), %si /* Establece el modo a no cero */ movb $1, -1(%si) movl ABS(stage2_sector), %ebx /* Establece el tamaño del dpa */ movw $0x0010, (%si) /* Los bloques*/ movw $1, 2(%si) /* La absoluta dirección.*/ movl %ebx, 8(%si) /* El segmento direccional de memoria. */ movw $STAGE1_BUFFERSEG, 6(%si) xorl %eax, %eax movw %ax, 4(%si) movl %eax, 12(%si) /* * Llama a la interrupción BIOS "INT 0x13 Función 0x42" para leer sectores * desde disco y almacenarlos en memoria * * Llama con: %ah = 0x42 %dl = Numero controlador 150 * * %ds:%si = segmento:desplazamiento de dpa Retorna: * %al = 0x0 satisfactorio; error código de falla */ movb $0x42, %ah int $0x13 /* Si LBA no es soportado intenta con el esquema CHS */ jc chs_mode movw $STAGE1_BUFFERSEG, %bx jmp copy_buffer chs_mode: /* * Determina la geometría del disco duro con ayuda de interrupciones * de la BIOS! */ movb $8, %ah int $0x13 jnc final_init /* * En caso de fallar prueba con el controlador del Disquete */ testb $STAGE1_BIOS_HD_FLAG, %dl jz floppy_probe /* El disco duro tiene problemas y se imprime un mensaje de error */ jmp hd_probe_error 151 final_init movw $ABS(sectors), %si /* Establece el modo a cero */ movb $0, -1(%si) /* Guarda el número de cabeceras */ xorl %eax, %eax movb %dh, %al incw %ax movl %eax, 4(%si) xorw %dx, %dx movb %cl, %dl shlw $2, %dx movb %ch, %al movb %dh, %ah /* Guarda el número de cilindros */ incw %ax movw %ax, 8(%si) xorw %ax, %ax movb %dl, %al shrb $2, %al /* Guarda el número de sectores */ movl %eax, (%si) setup_sectors: /* Cargar el inicio del sector lógico (mitad inferior) */ movl ABS(stage2_sector), %eax /* Establece cero edx */ 152 xorl %edx, %edx /* Divide por el número de sectores */ divl (%si) /* Guarda el sector de inicio */ movb %dl, 10(%si) xorl %edx, %edx divl 4(%si) /* Divide por el número de cabeceras */ /* Guarda la cabecera de inicio*/ movb %dl, 11(%si) /* Guarda el cilindro de inicio */ movw %ax, 12(%si) /* Comprueba que la geometría sea la correcta*/ cmpw 8(%si), %ax jge geometry_error /* * El siguiente bloque configura la geometría del disco. */ /*Obtiene los bits de mayor precedencia del cilindro*/ movb 13(%si), %dl shlb $6, %dl /* recorre 6 bits a la izquierda */ movb 10(%si), %cl /* Obtiene el sector */ incb /* Normaliza el sector (sectores van %cl desde 1-N, a 0-(N-1) ) */ orb %dl, %cl 153 movb 12(%si), %ch /*Cilindros en ch */ /* Restablece dx */ popw %dx /* Numero de cabeceras */ movb 11(%si), %dh /* * Interrupción BIOS "INT 0x13 Función 0x2" lee sectores del disco y los * almacena en memoria * Parámetros: %ah = 0x2 * %al = número de sectores * %ch = cilindro * %cl = sector (bits 6-7 son los bits altos "cilindro") * %dh = cabecera * %dl = drive (0x80 para el disco doro, * 0x0 para el disquete) * * %es:%bx = segmento:desplazamiento de memoria Retorna: * %al = 0x0 satisfactorio; error código de falla */ movw $STAGE1_BUFFERSEG, %bx movw %bx, %es xorw %bx, %bx /* Establece bx=0 */ movw $0x0201, %ax /* función 2, leer 1 sector */ int $0x13 jc read_error movw %es, %bx copy_buffer: movw ABS(stage2_segment), %es 154 /* * Se apila ax y ds en caso de que etapa 2 * necesite utilizar estos valores. */ pusha pushw %ds movw $0x100, %cx movw %bx, %ds xorw %si, %si xorw %di, %di cld rep movsw popw %ds popa /* Inicia Etapa 2*/ jmp *(stage2_address) /*Fin de la Etapa 1 */ /* * Error en la traducción en la geometría del BIOS. */ geometry_error: MSG(geometry_error_string) jmp general_error /* * Error prueba del disco fallo. 155 */ hd_probe_error: MSG(hd_probe_error_string) jmp general_error /* * Error lectura sobre el disco. */ read_error: MSG(read_error_string) general_error: MSG(general_error_string) /* Crea un bucle infinito después de fallo irreparable */ stop: jmp stop notification_string: .string "MOD U. CENTRAL GRUB" geometry_error_string: .string "Geom" hd_probe_error_string: .string "Hard" read_error_string: .string "Read" general_error_string: .string " Error" /* * message: Imprime en pantalla la cadena apuntada por si */ /* * Usa BIOS "int 10H Función 0Eh" para escribir caracteres en modo * teletipo * %ah = 0xe %al = carácter * %bh = page %bl = color de fondo (modo gráfico) */ 156 1: movw $0x0001, %bx movb $0xe, %ah int $0x10 message: lodsb cmpb $0, %al jne 1b /* Si no finaliza cadena repite bucle*/ ret /* * Windows NT rompe compatibilidad se embebe un * Número especial aquí. */ . = _start + STAGE1_WINDOWS_NT_MAGIC nt_magic: .long 0 .word 0 part_start: . = _start + STAGE1_PARTSTART probe_values: .byte 36, 18, 15, 9, 0 floppy_probe: /* * Realiza prueba de disquete. */ movw $ABS(probe_values-1), %si probe_loop: 157 /* Resetea controlador de disquete INT 13h AH=0 */ xorw %ax, %ax int $0x13 incw %si movb (%si), %cl /* Si el número de sectores es cero imprime mensaje de error. */ cmpb $0, %cl jne 1f MSG(fd_probe_error_string) jmp general_error fd_probe_error_string: .string "Floppy" 1: /* Lectura Realizada*/ movw $STAGE1_BUFFERSEG, %bx movw $0x201, %ax movb $0, %ch movb $0, %dh int $0x13 /* Si existe error salta a la etiqueta "probe_loop" */ jc probe_loop movb $1, %dh movb $79, %ch jmp final_init . = _start + STAGE1_PARTEND /* Los dos últimos bytes deben contener la firma que indica que es arrancable*/ .word STAGE1_SIGNATURE Archivo: Stage1.S 158 3.6.2 Modificación del Archivo stage1.h Archivo Stage1.h /* * SISTEMA : GRUB LEGACY MODIFICADO * MODULO : UNIVERSIDAD CENTRAL DEL ECUADOR * PROCESO : Stage1.h * DESCRIPCIÓN : Cabecera del archivo stage1.S, contiene etiquetas de * definiciones para poder compilar el archivo stage1.S * ANALISTAS : Ing. Mauro Rosas, Ing. Jairo Navarro, Ing. Jorge Morales * PROGRAMADOR : FIGUEROA CAÑAR VICTOR BOLÍVAR * FECHA CREACIÓN, MODIFICACIÓN: 05 de Abril del 2015 * LICENCIA: GNU GPL versión 2 o mayor. */ #ifndef STAGE1_HEADER #define STAGE1_HEADER 1 /* Se define el número de versión, tal que Stage1 pueda conocer este. */ #define COMPAT_VERSION_MAJOR 3 #define COMPAT_VERSION_MINOR 2 #define COMPAT_VERSION ((COMPAT_VERSION_MINOR << 8) \ | COMPAT_VERSION_MAJOR) /* La firma que identifica al MBR */ #define STAGE1_SIGNATURE 0xaa55 /* El desplazamiento en bytes al terminar el BPB (BIOS Parameter Block). */ #define STAGE1_BPBEND 0x3e /* El desplazamiento en bytes de la mayor versión */ 159 #define STAGE1_VER_MAJ_OFFS 0x3e /* El desplazamiento de BOOT_DRIVE. */ #define STAGE1_BOOT_DRIVE 0x40 /* El desplazamiento de FORCE_LBA. */ #define STAGE1_FORCE_LBA 0x41 /* El desplazamiento de STAGE2_ADDRESS. */ #define STAGE1_STAGE2_ADDRESS 0x42 /* El desplazamiento de STAGE2_SECTOR. */ #define STAGE1_STAGE2_SECTOR 0x44 /* El desplazamiento de STAGE2_SEGMENT. */ #define STAGE1_STAGE2_SEGMENT 0x48 /* El desplazamiento de BOOT_DRIVE_CHECK. */ #define STAGE1_BOOT_DRIVE_CHECK 0x4b /* The offset of a magic number used by Windows NT. */ #define STAGE1_WINDOWS_NT_MAGIC 0x1b8 /* El desplazamiento del inicio de la tabla de partición. */ #define STAGE1_PARTSTART 0x1be /* El desplazamiento del fin de la tabla de partición. */ #define STAGE1_PARTEND 0x1fe /* The segmento de pila. */ #define STAGE1_STACKSEG 0x2000 160 /* El segmento de memoria de disco. La memoria de disco debe ser 32K de longitud como mínimo */ #define STAGE1_BUFFERSEG 0x7000 /* La dirección de los parámetros del controlador */ #define STAGE1_DRP_ADDR 0x7f00 /* El tamaño total de los parámetros del controlador */ #define STAGE1_DRP_SIZE 0x42 /* La bandera para el numero controlador de la BIOS a designar un disco duro o un disquete */ #define STAGE1_BIOS_HD_FLAG 0x80 /* El numero de un controlador invalido. */ #define GRUB_INVALID_DRIVE 0xFF #endif Archivo: Stage1.h 161 3.6.3 Modificación del Archivo char_io.c Archivo char_io.c /* * SISTEMA : GRUB LEGACY MODIFICADO * MODULO : UNIVERSIDAD CENTRAL DEL ECUADOR * PROCESO: char_io.c * DESCRIPCIÓN: Rutinas en lenguaje c de ingreso de datos a través del teclado, formas de representar mensajes en pantalla. Manejo de errores en datos Etc. * ANALISTAS : Ing. Mauro Rosas, Ing. Jairo Navarro, Ing. Jorge Morales * PROGRAMADOR : FIGUEROA CAÑAR VICTOR BOLÍVAR * FECHA CREACIÓN, MODIFICACIÓN: 05 de Abril del 2015 * LICENCIA: GNU GPL versión 2 o mayor. */ #include <shared.h> #include <term.h> #ifdef SUPPORT_HERCULES # include <hercules.h> #endif #ifdef SUPPORT_SERIAL # include <serial.h> #endif #ifndef STAGE1_5 struct term_entry term_table[] = { { "console", 0, console_putchar, console_checkkey, 162 console_getkey, console_getxy, console_gotoxy, console_cls, console_setcolorstate, console_setcolor, console_setcursor }, #ifdef SUPPORT_SERIAL { "serial", /* Un serial dispositivo debe ser inicializado.*/ TERM_NEED_INIT, serial_putchar, serial_checkkey, serial_getkey, serial_getxy, serial_gotoxy, serial_cls, serial_setcolorstate, 0, 0 }, #endif /* Soporte Serial*/ #ifdef SUPPORT_HERCULES { "hercules", 0, hercules_putchar, console_checkkey, console_getkey, hercules_getxy, 163 hercules_gotoxy, hercules_cls, hercules_setcolorstate, hercules_setcolor, hercules_setcursor }, #endif /* Soporte Hercules */ /* Esta debe ser la última entrada */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; /* This must be console. */ struct term_entry *current_term = term_table; int max_lines = 24; int count_lines = -1; int use_pager = 1; #endif void print_error (void) { if (errnum > ERR_NONE && errnum < MAX_ERR_NUM) #ifndef STAGE1_5 /* llama al método printf("\7\n %s\n", err_list[errnum]); */ printf ("\nError %u: %s\n", errnum, err_list[errnum]); #else /* STAGE1_5 */ printf ("Error %u\n", errnum); #endif /* STAGE1_5 */ } 164 char * convert_to_ascii (char *buf, int c,...) { unsigned long num = *((&c) + 1), mult = 10; char *ptr = buf; #ifndef STAGE1_5 if (c == 'x' || c == 'X') mult = 16; if ((num & 0x80000000uL) && c == 'd') { num = (~num) + 1; *(ptr++) = '-'; buf++; } #endif do { int dig = num % mult; *(ptr++) = ((dig > 9) ? dig + 'a' - 10 : '0' + dig); } while (num /= mult); /* Reordena a la correcta dirección. */ { char *ptr1 = ptr - 1; char *ptr2 = buf; while (ptr1 > ptr2) { int tmp = *ptr1; 165 *ptr1 = *ptr2; *ptr2 = tmp; ptr1--; ptr2++; } } return ptr; } void grub_putstr (const char *str) { while (*str) grub_putchar (*str++); } void grub_printf (const char *format,...) { int *dataptr = (int *) &format; char c, str[16]; dataptr++; while ((c = *(format++)) != 0) { if (c != '%') grub_putchar (c); else switch (c = *(format++)) { #ifndef STAGE1_5 case 'd': case 'x': 166 case 'X': #endif case 'u': *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; grub_putstr (str); break; #ifndef STAGE1_5 case 'c': grub_putchar ((*(dataptr++)) & 0xff); break; case 's': grub_putstr ((char *) *(dataptr++)); break; #endif } } } #ifndef STAGE1_5 int grub_sprintf (char *buffer, const char *format, ...) { /* Emula unificacion con printf() */ int *dataptr = (int *) &format; char c, *ptr, str[16]; char *bp = buffer; dataptr++; while ((c = *format++) != 0) 167 { if (c != '%') *bp++ = c; /* apila(c); */ else switch (c = *(format++)) { case 'd': case 'u': case 'x': *convert_to_ascii (str, c, *((unsigned long *) dataptr++)) = 0; ptr = str; while (*ptr) *bp++ = *(ptr++); /* putchar(*(ptr++)); */ break; case 'c': *bp++ = (*(dataptr++))&0xff; /* Apila((*(dataptr++))&0xff); */ break; case 's': ptr = (char *) (*(dataptr++)); while ((c = *ptr++) != 0) *bp++ = c; /* Apila(c); */ break; } } *bp = 0; return bp - buffer; } 168 void init_page (void) { cls (); grub_printf ("\n AUTOR: vfigueroa GRUB MODIFICADO versión 0.01 (%dK baja / %dK alta memoria)\n\n", mbi.mem_lower, mbi.mem_upper); } /* El número de entradas de la historia. */ static int num_history = 0; static char * get_history (int no) { if (no < 0 || no >= num_history) return 0; return (char *) HISTORY_BUF + MAX_CMDLINE * no; } /* Adiciona CMDLINE a la historia del buffer. */ static void add_history (const char *cmdline, int no) { grub_memmove ((char *) HISTORY_BUF + MAX_CMDLINE * (no + 1), (char *) HISTORY_BUF + MAX_CMDLINE * no, MAX_CMDLINE * (num_history - no)); grub_strcpy ((char *) HISTORY_BUF + MAX_CMDLINE * no, cmdline); if (num_history < HISTORY_SIZE) num_history++; 169 } static int real_get_cmdline (char *prompt, char *cmdline, int maxlen, int echo_char, int readline) { /* Esta función es complicada tal que se explicara el concepto. * Una sección es una parte de la línea que debe ser mostrada en * pantalla, pero una sección nunca es mostrada con otra sección * simultáneamente. * Cada sección es básicamente 77 caracteres o menos, pero la excepción * es la primera sección, que es 78 o menos caracteres, porque el * punto de partida es especial. Se detalla más abajo. * La primera sección contiene un prompt y una línea de comandos (o la * primera parte de una línea de comandos cuando es demasiado largo para * estar en pantalla). Así, en la primera sección, el número de caracteres * de la línea de comandos desplegados es de 78 menos el largo del prommpt * (o menor) * Si la linea de comandos tiene más caracteres , '>' is puesto a la * posición 78 (cero original),para informar al usuario de los caracteres * escondidos. * Otras secciones siempre tienen '<' en la primera posición, ya que allí * Esta absolutamente una sección antes de cada sección. Si esta es una * sección después de otra sección, esta sección consiste de 77 caracteres * Y el símbolo '>' en la última posición. La ultima sección tiene 77 o * menos caracteres y no tiene el símbolo '>' * Cada otra sección distinta de las ultimas compartes algunos caracteres * Con la sección previa. Esta región es llamada 'margen'. Si el cursor es * puesto a él margen que es compartido por la primera sección y la segunda, * La primera sección es desplegada. caso contrario la sección desplegada es * cambiada a la otra sección, solo si el cursor es puesto fuera de la seccion. 170 */ #define CMDLINE_WIDTH 78 #define CMDLINE_MARGIN 10 int xpos, lpos, c, section; /* El tamaño del PROMPT. */ int plen; /* El tamaño de la linea de comandos. */ int llen; /* El índice para la historia */ int history = -1; /* La sección de memoria de trabajo para la linea de comandos */ char *buf = (char *) CMDLINE_BUF; /* Limpieza de la memoria */ char *kill_buf = (char *) KILL_BUF; /*Las declaraciones de las funciones anidadas son prefijadas con * la etiqueta 'auto' */ auto void cl_refresh (int full, int len); auto void cl_backward (int count); auto void cl_forward (int count); auto void cl_insert (const char *str); auto void cl_delete (int count); auto void cl_init (void); /* Retrocede al cursor */ void cl_backward (int count) 171 { lpos -= count; /* Si el cursor está en la primera sección, despliega la primera sección * en lugar de la segunda */ if (section == 1 && plen + lpos < CMDLINE_WIDTH) cl_refresh (1, 0); else if (xpos - count < 1) cl_refresh (1, 0); else { xpos -= count; if (current_term->flags & TERM_DUMB) { int i; for (i = 0; i < count; i++) grub_putchar ('\b'); } else gotoxy (xpos, getxy () & 0xFF); } } /* Retrocede al cursor */ void cl_forward (int count) { lpos += count; /* Si el cursor sale de pantalla, desplaza la pantalla hacia la * derecha. */ if (xpos + count >= CMDLINE_WIDTH) 172 cl_refresh (1, 0); else { xpos += count; if (current_term->flags & TERM_DUMB) { int i; for (i = lpos - count; i < lpos; i++) { if (! echo_char) grub_putchar (buf[i]); else grub_putchar (echo_char); } } else gotoxy (xpos, getxy () & 0xFF); } } /* Limpia la pantalla. Si FULL es verdadero, redibuja el full linea, * caso contrario, solo LEN caracteres desde LPOS. */ void cl_refresh (int full, int len) { int i; int start; int pos = xpos; if (full) { /* Recalcula la sección numérica. */ if (lpos + plen < CMDLINE_WIDTH) 173 section = 0; else section = ((lpos + plen - CMDLINE_WIDTH) / (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + 1); /* Desde el inicio al final. */ len = CMDLINE_WIDTH; pos = 0; grub_putchar ('\r'); /* Si esta sección es la primera, Imprime el prompt, caso contrario, * imprime '<'. */ if (section == 0) { grub_printf ("%s", prompt); len -= plen; pos += plen; } else { grub_putchar ('<'); len--; pos++; } } /* Calcula el índice al iniciar escribiendo BUF y el resultado lo *coloca sobre la pantalla. */ if (section == 0) { int offset = 0; 174 if (! full) offset = xpos - plen; start = 0; xpos = lpos + plen; start += offset; } else { int offset = 0; if (! full) offset = xpos - 1; start = ((section - 1) * (CMDLINE_WIDTH - 1 - CMDLINE_MARGIN) + CMDLINE_WIDTH - plen - CMDLINE_MARGIN); xpos = lpos + 1 - start; start += offset; } /* Imprime BUF. Si ECHO_CHAR no es cero, lo coloca en otro lugar */ for (i = start; i < start + len && i < llen; i++) { if (! echo_char) grub_putchar (buf[i]); else grub_putchar (echo_char); pos++; } /* Llena el resto de líneas con espacios. */ for (; i < start + len; i++) { grub_putchar (' '); 175 pos++; } /*S el cursor está en la última posición, coloca '>' o un espacio, dependiendo de la cantidad de caracteres en BUF. */ if (pos == CMDLINE_WIDTH) { if (start + len < llen) grub_putchar ('>'); else grub_putchar (' '); pos++; } /* Regresa a XPOS. */ if (current_term->flags & TERM_DUMB) { for (i = 0; i < pos - xpos; i++) grub_putchar ('\b'); } else gotoxy (xpos, getxy () & 0xFF); } /* Inicializa la linea de comandos. */ void cl_init (void) { /* No distingue de otras líneas y mensajes de error */ grub_putchar ('\n'); /* Imprime todas las líneas y establece la posición aquí */ cl_refresh (1, 0); 176 } /* Inserta STR a BUF. */ void cl_insert (const char *str) { int l = grub_strlen (str); if (llen + l < maxlen) { if (lpos == llen) grub_memmove (buf + lpos, str, l + 1); else { grub_memmove (buf + lpos + l, buf + lpos, llen - lpos + 1); grub_memmove (buf + lpos, str, l); } llen += l; lpos += l; if (xpos + l >= CMDLINE_WIDTH) cl_refresh (1, 0); else if (xpos + l + llen - lpos > CMDLINE_WIDTH) cl_refresh (0, CMDLINE_WIDTH - xpos); else cl_refresh (0, l + llen - lpos); } } /* Elimina COUNT caracteres en BUF. */ void cl_delete (int count) { grub_memmove (buf + lpos, buf + lpos + count, llen - count + 1); llen -= count; 177 if (xpos + llen + count - lpos > CMDLINE_WIDTH) cl_refresh (0, CMDLINE_WIDTH - xpos); else cl_refresh (0, llen + count - lpos); } plen = grub_strlen (prompt); llen = grub_strlen (cmdline); if (maxlen > MAX_CMDLINE) { maxlen = MAX_CMDLINE; if (llen >= MAX_CMDLINE) { llen = MAX_CMDLINE - 1; cmdline[MAX_CMDLINE] = 0; } } lpos = llen; grub_strcpy (buf, cmdline); cl_init (); while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r') { /* Si READLINE es no cero, maneja readline como clave de enlace. */ if (readline) { switch (c) { case 9: { int i; /* POS puntos del primer espacio después de un comando. */ 178 int pos = 0; int ret; char *completion_buffer = (char *) COMPLETION_BUF; int equal_pos = -1; int is_filename; /* Encuentra la primera palabra. */ while (buf[pos] == ' ') pos++; while (buf[pos] && buf[pos] != '=' && buf[pos] != ' ') pos++; is_filename = (lpos > pos); /* Encuentra la posición del carácter '=' después de un *comando, y reemplaza esta con un espacio. */ for (i = pos; buf[i] && buf[i] != ' '; i++) if (buf[i] == '=') { equal_pos = i; buf[i] = ' '; break; } /* Encuentra la posición del primer carácter en esta * palabra */ for (i = lpos; i > 0 && buf[i - 1] != ' '; i--) ; /* Invalida la cache, a causa el usuario debe cambiar discos *removibles */ buf_drive = -1; /* Copia esta palabra a COMPLETION_BUFFER y la * completa. */ 179 grub_memmove (completion_buffer, buf + i, lpos - i); completion_buffer[lpos - i] = 0; ret = print_completions (is_filename, 1); errnum = ERR_NONE; if (ret >= 0) { /* Encuentra, para insertar COMPLETION_BUFFER. */ cl_insert (completion_buffer + lpos - i); if (ret > 0) { /* Si hay más que un candidato, entonces imprime * la lista. */ grub_putchar ('\n'); print_completions (is_filename, 0); errnum = ERR_NONE; } } /* Restaura la linea de comandos. */ if (equal_pos >= 0) buf[equal_pos] = '='; if (ret) cl_init (); } break; case 1: /* C-a ir al principio de la linea */ cl_backward (lpos); break; case 5: /* C-e ir al final de la linea */ cl_forward (llen - lpos); 180 break; case 6: /* C-f adelantar un carácter */ if (lpos < llen) cl_forward (1); break; case 2: /* C-b retroceder un caracter */ if (lpos > 0) cl_backward (1); break; case 21: /* C-u Limpiar el inicio de la linea */ if (lpos == 0) break; /* Copiar la cadena que se va a eliminar a KILL_BUF. */ grub_memmove (kill_buf, buf, lpos); kill_buf[lpos] = 0; { int count = lpos; cl_backward (lpos); cl_delete (count); } break; case 11: /* C-k Limpiar el final de la linea */ if (lpos == llen) break; /* Copiar la cadena que se va a eliminar a KILL_BUF. */ grub_memmove (kill_buf, buf + lpos, llen - lpos + 1); cl_delete (llen - lpos); break; case 25: /* C-y Eliminar buffer */ cl_insert (kill_buf); break; case 16: /* C-p buscar el comando anterior */ 181 { char *p; if (history < 0) /* Guarda el buffer trabajado. */ grub_strcpy (cmdline, buf); else if (grub_strcmp (get_history (history), buf) != 0) /* Si BUF es modificado, adicionar este dentro de la lista * historia. */ add_history (buf, history); history++; p = get_history (history); if (! p) { history--; break; } grub_strcpy (buf, p); llen = grub_strlen (buf); lpos = llen; cl_refresh (1, 0); } break; case 14: /* C-n buscar el comando anterior */ { char *p; if (history < 0) { break; } else if (grub_strcmp (get_history (history), buf) != 0) /* Si BUF es modificado, adicionar este dentro de la lista historia */ 182 add_history (buf, history); history--; p = get_history (history); if (! p) p = cmdline; grub_strcpy (buf, p); llen = grub_strlen (buf); lpos = llen; cl_refresh (1, 0); } break; } } /* ESC, C-d y C-h son siempre manejadores. Actualmente C-d no esta * funcional si READLINE es cero, como el cursor no puede * retroceder. */ switch (c) { case 27: /* ESC inmediatamente retorna a 1 */ return 1; case 4: /* C-d Elimina carácter bajo cursor */ if (lpos == llen) break; cl_delete (1); break; case 8: /* C-h Tecla espaceadora */ # ifdef GRUB_UTIL case 127: /* also Tecla espaceadora */ # endif if (lpos > 0) 183 { cl_backward (1); cl_delete (1); } break; default: /* Inserta imprimibles caracteres dentro de la linea */ if (c >= ' ' && c <= '~') { char str[2]; str[0] = c; str[1] = 0; cl_insert (str); } } } grub_putchar ('\n'); /* Si ECHO_CHAR es NUL, remueve los espacios primarios. */ lpos = 0; if (! echo_char) while (buf[lpos] == ' ') lpos++; /* Copia el buffer de trabajo a CMDLINE. */ *grub_memmove (cmdline, buf + lpos, llen - lpos + 1); /* Si la readline como característica es encendida and CMDLINE no es * vacío, adiciona este dentro de la lista de historia. */ if (readline && lpos < llen) add_history (cmdline, 0); 184 return 0; } /* No usar esto con MAXLEN mayor que 1600 o superior. El problema * es que GET_CMDLINE depende sobre el tamaño apropiado de la pantalla. * Por lo tanto toda pantalla es de unos 2000 caracteres, menos el * PROMPT, y espacio para errores y líneas de estatus, etc. MAXLEN debe ser * al menos uno, y PROMPT y CMDLINE deben ser cadenas validas(not nulas * or de cero longitud). * Si ECHO_CHAR es no cero, echo está en lugar del carácter escrito. */ int get_cmdline (char *prompt, char *cmdline, int maxlen, int echo_char, int readline) { int old_cursor; int ret; old_cursor = setcursor (1); /* Debido a que es difícil tratar con diferentes situaciones * simultáneamente, casos menos funcionales se manejan aquí. * Asumo que TERM_NO_ECHO * implica TERM_NO_EDIT. */ if (current_term->flags & (TERM_NO_ECHO | TERM_NO_EDIT)) { char *p = cmdline; int c; /* Aseguramos que MAXLEN no es muy largo. */ if (maxlen > MAX_CMDLINE) maxlen = MAX_CMDLINE; 185 /* Imprimimos solo el prompt. El contenido de CMDLINE es simplemente * descartado, dado si este no es vacío. */ grub_printf ("%s", prompt); /* Reúne caracteres hasta que se incorpore una nueva linea. */ while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r') { /* Retorna inmediatamente si ESC es presionada. */ if (c == 27) { setcursor (old_cursor); return 1; } /* Imprimibles caracteres son adicionados dentro de CMDLINE. */ if (c >= ' ' && c <= '~') { if (! (current_term->flags & TERM_NO_ECHO)) grub_putchar (c); /* Caracteres espacios precedentes deben ser ignorados. */ if (c != ' ' || p != cmdline) *p++ = c; } } *p = 0; if (! (current_term->flags & TERM_NO_ECHO)) grub_putchar ('\n'); setcursor (old_cursor); return 0; } 186 /* Complicadas características se dejan a real_get_cmdline. */ ret = real_get_cmdline (prompt, cmdline, maxlen, echo_char, readline); setcursor (old_cursor); return ret; } int safe_parse_maxint (char **str_ptr, int *myint_ptr) { char *ptr = *str_ptr; int myint = 0; int mult = 10, found = 0; if (*ptr == '0' && tolower (*(ptr + 1)) == 'x') { ptr += 2; mult = 16; } while (1) { /* Esta continuación hace uso de la equivalencia: * (A >= B && A <= C) <=> ((A - B) <= (C - B)) * cuando C > B y A es sin signo. */ unsigned int digit; digit = tolower (*ptr) - '0'; if (digit > 9) { digit -= 'a' - '0'; if (mult == 10 || digit > 5) 187 break; digit += 10; } found = 1; if (myint > ((MAXINT - digit) / mult)) { errnum = ERR_NUMBER_OVERFLOW; return 0; } myint = (myint * mult) + digit; ptr++; } if (!found) { errnum = ERR_NUMBER_PARSING; return 0; } *str_ptr = ptr; *myint_ptr = myint; return 1; } #endif /* STAGE1_5 */ #if !defined(STAGE1_5) || defined(FSYS_FAT) int grub_tolower (int c) { if (c >= 'A' && c <= 'Z') 188 return (c + ('a' - 'A')); return c; } #endif /* ! STAGE1_5 || FSYS_FAT */ int grub_isspace (int c) { switch (c) { case ' ': case '\t': case '\r': case '\n': return 1; default: break; } return 0; } #if !defined(STAGE1_5) || defined(FSYS_ISO9660) int grub_memcmp (const char *s1, const char *s2, int n) { while (n) { if (*s1 < *s2) return -1; else if (*s1 > *s2) return 1; s1++; s2++; n--; 189 } return 0; } #endif /* ! STAGE1_5 || FSYS_ISO9660 */ #ifndef STAGE1_5 int grub_strncat (char *s1, const char *s2, int n) { int i = -1; while (++i < n && s1[i] != 0); while (i < n && (s1[i++] = *(s2++)) != 0); s1[n - 1] = 0; if (i >= n) return 0; s1[i] = 0; return 1; } #endif /* ! STAGE1_5 */ #if !defined(STAGE1_5) || defined(FSYS_VSTAFS) int grub_strcmp (const char *s1, const char *s2) { while (*s1 || *s2) { if (*s1 < *s2) return -1; else if (*s1 > *s2) return 1; s1 ++; s2 ++; } 190 return 0; } #endif /* ! STAGE1_5 || FSYS_VSTAFS */ #ifndef STAGE1_5 /* Espera a pulsar una tecla y retornar al código. */ int getkey (void) { return current_term->getkey (); } /* Compruebe si el código clave está disponible. */ int checkkey (void) { return current_term->checkkey (); } #endif /* ! STAGE1_5 */ /* Despliega un ASCII carácter. */ void grub_putchar (int c) { if (c == '\n') grub_putchar ('\r'); #ifndef STAGE1_5 else if (c == '\t' && current_term->getxy) { int n; 191 n = 8 - ((current_term->getxy () >> 8) & 3); while (n--) grub_putchar (' '); return; } #endif /* ! STAGE1_5 */ #ifdef STAGE1_5 /* In Stage 1.5, solo el normal consola es soportado. */ console_putchar (c); #else /* ! STAGE1_5 */ if (c == '\n') { /* Interno 'more' como caracteristica. */ if (count_lines >= 0) { count_lines++; if (count_lines >= max_lines - 2) { int tmp; /* Es importante desactivar las características temporalmente, * a causa la siguiente llamada a grub_printf deberá imprimir * nuevas lineas. */ count_lines = -1; if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_HIGHLIGHT); grub_printf ("\n[Hit return to continue]"); 192 if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_NORMAL); do { tmp = ASCII_CHAR (getkey ()); } while (tmp != '\n' && tmp != '\r'); grub_printf ("\r \r"); /* Reinicia el conteo de líneas. */ count_lines = 0; return; } } } current_term->putchar (c); #endif /* ! STAGE1_5 */ } #ifndef STAGE1_5 void gotoxy (int x, int y) { current_term->gotoxy (x, y); } int getxy (void) { return current_term->getxy (); } 193 void cls (void) { /* Si el terminal esta inhibido, no hay manera de limpiar el terminal. */ if (current_term->flags & TERM_DUMB) grub_putchar ('\n'); else current_term->cls (); } int setcursor (int on) { if (current_term->setcursor) return current_term->setcursor (on); return 1; } #endif /* ! STAGE1_5 */ int substring (const char *s1, const char *s2) { while (*s1 == *s2) { /* Enlaza las cadenas exactamente. */ if (! *(s1++)) return 0; s2 ++; } /* S1 es una subcadena de S2. */ 194 if (*s1 == 0) return -1; /* S1 no es una subcadena. */ return 1; } #ifndef STAGE1_5 /* Termina la cadena STR con NUL. */ int nul_terminate (char *str) { int ch; while (*str && ! grub_isspace (*str)) str++; ch = *str; *str = 0; return ch; } char * grub_strstr (const char *s1, const char *s2) { while (*s1) { const char *ptr, *tmp; ptr = s1; tmp = s2; while (*tmp && *ptr == *tmp) ptr++, tmp++; if (tmp > s2 && ! *tmp) return (char *) s1; 195 s1++; } return 0; } int grub_strlen (const char *str) { int len = 0; while (*str++) len++; return len; } #endif /* ! STAGE1_5 */ int memcheck (int addr, int len) { #ifdef GRUB_UTIL auto int start_addr (void); auto int end_addr (void); auto int start_addr (void) { int ret; # if defined(HAVE_START_SYMBOL) asm volatile ("movl $start, %0" : "=a" (ret)); # elif defined(HAVE_USCORE_START_SYMBOL) asm volatile ("movl $_start, %0" : "=a" (ret)); # endif return ret; } 196 auto int end_addr (void) { int ret; # if defined(HAVE_END_SYMBOL) asm volatile ("movl $end, %0" : "=a" (ret)); # elif defined(HAVE_USCORE_END_SYMBOL) asm volatile ("movl $_end, %0" : "=a" (ret)); # endif return ret; } if (start_addr () <= addr && end_addr () > addr + len) return ! errnum; #endif /* GRUB_UTIL */ if ((addr < RAW_ADDR (0x1000)) || (addr < RAW_ADDR (0x100000) && RAW_ADDR (mbi.mem_lower * 1024) < (addr + len)) || (addr >= RAW_ADDR (0x100000) && RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len))) errnum = ERR_WONT_FIT; return ! errnum; } void * grub_memmove (void *to, const void *from, int len) { if (memcheck ((int) to, len)) { int d0, d1, d2; 197 if (to < from) { asm volatile ("cld\n\t" "rep\n\t" "movsb" : "=&c" (d0), "=&S" (d1), "=&D" (d2) : "0" (len),"1" (from),"2" (to) : "memory"); } else { asm volatile ("std\n\t" "rep\n\t" "movsb\n\t" "cld" : "=&c" (d0), "=&S" (d1), "=&D" (d2) : "0" (len), "1" (len - 1 + (const char *) from), "2" (len - 1 + (char *) to) : "memory"); } } return errnum ? NULL : to; } void * grub_memset (void *start, int c, int len) { char *p = start; if (memcheck ((int) start, len)) 198 { while (len -- > 0) *p ++ = c; } return errnum ? NULL : start; } #ifndef STAGE1_5 char * grub_strcpy (char *dest, const char *src) { grub_memmove (dest, src, grub_strlen (src) + 1); return dest; } #endif /* ! STAGE1_5 */ #ifndef GRUB_UTIL # undef memcpy /* GCC emite referencias a memcpy() para estructurar copias etc. */ void *memcpy (void *dest, const void *src, int n) __attribute__ ((alias ("grub_memmove"))); #endif Archivo char_io.c 3.6.4 Presentación Del funcionamiento De Grub Legacy Modificado. En las siguientes imágenes se presenta el funcionamiento del gestor de arranque Grub Legacy Modificado. Una vez que Grub Legacy Modificado ha sido inyectado en un dispositivo de almacenamiento (CD, USB, Disco Duro etc). 199 3.6.4.1 Pantalla Inicial Grub Legacy Modificado La siguiente pantalla se muestra al iniciar Grub Legacy Modificado. Figura 49. Inico Grub Legacy Modificado. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 3.6.4.2 Grub Legacy Modificado Chainloader En la siguiente pantalla muestra los comandos necesarios para iniciar un sistema operativo que no sea de distribución GNU/Linux. Figura 50. Inico Grub Legacy Chainloader. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 200 Nota: Grub Legacy Modificado acepta los mismos comandos que Grub Legacy ya que es un clon. 3.7 Desarrollo de MUCE (MBR de la Universidad Central del Ecuador) Muce es un Master Boot Record para computadores compatibles x86 que inician en modo real, MUCE es construido en el estudio, investigación y desarrollo del presente tema de tesis. El código de MUCE es de licencia GNU GPL, y está bajo los derechos de código de temas de tesis de la Universidad Central del Ecuador. En el código de MUCE se encuentra disponible a la comunidad en la página web: www.softwaredesarrollo.com, y en el presente documento de tema de tesis. 3.7.1 Código de MUCE Archivo Código de MUCE /* * SISTEMA : MUCE (MBR Universidad Central del Ecuador) * MODULO : UNIVERSIDAD CENTRAL DEL ECUADOR * PROCESO : Etapa 1 MUCE * DESCRIPCIÓN : Master Boot record en lenguaje ensamblador que permite * arrancar desde un dispositivo de almacenamiento, y su función es * copiar los primeros 512 bytes a otra parte de la memoria para cargar * el sector de arranque del disco duro a memoria y cederle el * procesamiento. * ANALISTAS : Ing. Mauro Rosas, Ing. Jairo Navarro, Ing. Jorge Morales * PROGRAMADOR : FIGUEROA CAÑAR VICTOR BOLÍVAR * FECHA CREACIÓN, MODIFICACIÓN: 05 de Abril del 2015 * LICENCIA: GNU GPL versión 2 o mayor. 201 */ .code16 .section .text .globl _start _start: movw $512, %cx /*Establece cx=512 para mover 512 bytes de *memoria*/ movw $0x7c00, %bx/*Establece el inicio de dirección de memoria *de donde se comenzara a copiar los datos*/ /* El siguiente código copia los datos de la posición asignada a bx a un * desplazamiento de 512 bytes*/ cMem: movb (%bx), %ah movb %ah,0x0200(%bx) addw $0x0001,%bx loop cMem jmp ini+512/*Salta de la posición del segmento 0:7c00 a la *posición del segmento 0:7e00, como el código fue *movido a esta posición continua ejecutando el *mismo código pero en otra posición de memoria.*/ ini: movw $hello,%si call PrintString movb $0x02,%ah xorb %bh,%bh 202 movw $0x0100,%dx int $0x10 movw $prog,%si call PrintString movb $0x02,%ah xorb %bh,%bh movw $0x0200,%dx int $0x10 movw $muce,%si call PrintString movb $0x02,%ah xorb %bh,%bh movw $0x0400,%dx int $0x10 movw $press,%si call PrintString xorb %ah,%ah int $0x16 readSector: xorw %ax,%ax movw %ax, %es movb $0x02, %ah movb $0x01, %al movw $0x7C00,%bx xorb %ch,%ch movb $0x01,%cl movw $0x0080,%dx int $0x13 jc Error 203 movw $0x7C00,%bx movw (%bx),%ax call ImpHex jmp loop Error: call ImpHex jmp loop ImpHex: movw %ax, area movb $0x0C,%cl shrax: movw area,%ax shrw %cl,%ax andb $0x0F, %al cmpb $0x0A, %al jc IsNumber addb $0x37,%al call int10 jmp shraxbucle IsNumber: addb $0x30,%al call int10 shraxbucle: subb $0x04,%cl jnc shrax ret /*Inicio de proceso que imprime caracteres con la int 10h*/ PrintString: lodsb 204 cmpb $0x00, %al jnz Continue ret Continue: call int10 jmp PrintString int10: movb $0x0E,%ah int $0x10 ret /*Fin de Proceso de impresion*/ loop: cli xorw %ax,%ax movw %ax,%ds movw %ax,%es movw %ax,%ss sti jmp (0x7c00-512) jmp loop /*Mensajes de Impresion en la pantalla*/ hello: .string "AUTOR: UNIVERSIDAD CENTRAL DEL ECUADOR" prog: .string "PROGRAMADOR: Victor Figueroa" muce: .string "MBR MUCE" press: .string "Presione una tecla para iniciar desde el disco duro" area: .space, 100 .org 510 .byte 0x55 .byte 0xAA/*Firma del código MBR*/ Archivo Código de MUCE 205 CAPITULO 4 4.1 Pruebas 4.1.1 Presentación Funcionamiento MUCE En las siguientes capturas de pantalla se presenta el funcionamiento de MUCE. En general es un gestor de arranque básico, que una vez iniciado solicita el ingreso de un enter para cargar el MBR del disco duro. 4.1.1.1 Pantalla Inicial MUCE Figura 51. Inicio MUCE. Autor: Tesista. Fuente: Desarrollo de tema de tesis. 206 4.1.1.2 Pantalla Inicio Windows Xp Al dar enter iniciara el sistema operativo en este caso Windows xp. Figura 52. MUCE Iniciando XP Autor: Tesista. Fuente: Desarrollo de tema de tesis. 4.2 Conclusiones Con el desarrollo de los temas de tesis se puede concluir que una vez comprendido todo el funcionamiento interno de la computadora, el funcionamiento de los gestores de arranque todos tienen básicamente los mismos métodos de operación, por lo que una vez entendido y modificado un gestor de arranque se puede construir un clon o uno propio. Se concluye también que el acceso al disco duro a través de su tabla de particiones es un riesgo de seguridad de datos y un mecanismo de recuperación de datos, dependiendo de cómo se desee utilizar este mecanismo. La principal conclusión es que si se pudo investigar y modificar un gestor de arranque y algunos desarrolladores de gestores de arranque como grub opinan que es grub tiene la misma o mayor complejidad que el kernel de los sistema GNU/Linux, se puede desarrollar un sistema operativo. 207 4.3 Recomendaciones La importancia de generar un gestor de arranque y darle soporte por parte de una unidad educativa como la Universidad Central del Ecuador dotara de independencia en cuanto al software ya que este el inicio de todo desarrollo de software. Se debe estudiar tanto el código libre como el código propietario para encontrar similitudes y ventajas de un sistema respecto de otro. Así se pueden tomar mejores decisiones al momento de generar clones de sistema operativos. Se recomienda que todo software desarrollado este bajo licencia GPL, ya que esta da libertades a otros usuarios de estudiar, modificar y ejecutar el código como más crean conveniente. Por último se puede recomendar que si se tiene el ejecutable de un código se puede ejecutar herramientas de ingeniería inversa para ver cómo está estructurado el código, la lógica de su programación y con esto podemos realizar clones del software estudiado. 208 BIBLIOGRAFIA 1. WEB: Lenguaje Ensamblador: http://es.wikipedia.org/wiki/Lenguaje_ensamblador 2. Libro: Lenguaje C: KERNIGHAN, Brian Wilson & RITCHIE, Dennis Macalistair. (2008). El Lenguaje De Programación C. 3. WEB: Gestor de arranque: http://www.linuxeslibre.com.ar/tutos_pre_liloygrub.html http://www.codeproject.com/Articles/668422/Writing-a-boot-loader-inAssembly-and-C-Part. http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-inAssembly-and-C-Part http://thestarman.pcministry.com/asm/mbr/GRUB.htm https://elendill.wordpress.com/tag/mbr/ http://www.zator.com/Hardware/H8_1_2c.htm 4. Libro: Lenguaje Ensamblador, Nasm, Masm: CHARTE OJEDA, Francisco. (2009). Lenguaje ensamblador. 5. WEB: GRUB LEGACY http://gnu.ist.utl.pt/software/grub/grub-legacy-devel.en.html 209