Cómo actualizar el microcódigo, firmware y BIOS/UEFI – Parte 1/2

Firmware, BIOS/UEFI, microcódigo… varios términos para describir cosas que a veces son confusas para algunos usuarios. Pero son elementos vitales de una máquina, y pueden afectar a la seguridad, rendimiento y funcionamiento. Por eso, es importante mantenerlos actualizados. Algo que no hace la inmensa mayoría de usuarios por desconocimiento.

En este artículo podrás comprender las diferencias entre los términos, además de cómo puedes actualizar cada uno de ellos en tu sistema…

Más información sobre P.O.S.T. del BIOS/UEFI o sobre la secuencia de arranque.

¿Qué es el firmware?

firmware

Todos tienen bastante claro qué es el SW/HW de una computadora. Mientras el hardware es la parte física y palpable del equipo, el software es la parte lógica (programas) que no se puede tocar. Un tándem casi inseparable cuando se trata de electrónica programada (no cableada), el uno sin el otro no sirven de nada.

Sin embargo, lo que no tienen tan claro es qué es eso del firmware. Una capa intermedia entre el software y el hardware, pero que también es vital para que todo funcione correctamente. Básicamente es una rutina o programa sencillo, un código que se carga en una memoria tipo ROM programable o flash. Su objetivo es que el hardware «sepa» qué es lo que tiene que hacer, actuando de intermediario entre el hardware y los controladores del sistema operativo.

El término sería acuñado por Ascher Opler, en un artículo de la revista Datamation de 1967, aunque en aquel momento se refiería a algo muy específico. La etimología indica que es un «software firme o fijo» (del inglés firm+software). Actualmente, ese término se usa más ampliamente para llamar a todo aquello que ni es software ni es hardware, o mejor dicho, es software (puesto que es un programa) y hardware (puesto que siempre está en chips) a la vez.

El firmware también está presente en otros muchos sistemas que incluyen computadoras. Como los vehículos, TVs, lavadoras, etc.

Este firmware está presente en casi todos los dispositivos de hardware. Lo está en los medios de almacenamiento, en los routers, en los periféricos de entrada y salida, e incluso en la CPU (el famoso microcódigo).

Además, muchas computadoras también tienen otro firmware más avanzado e importante que se encarga de hacer que todos los componentes, aunque sean de diferentes marcas, funcionen de forma conjunta. También es el encargado de implementar la rutina de arranque para que todo comience a funcionar, y de encontrar y ceder el control al kernel del sistema operativo (u otros programas bare-metal) para cargarlo en memoria y comience su ejecución.

Me estoy refiriendo al BIOS o al actual EFI/UEFI. Éste último ha venido a sustituir a los primitivos BIOS, mejorando algunos de los problemas que han arrastrado históricamente.

Firmware de los componentes y periféricos

Chips de memoria EPROM que puede ser borrada por UV

El firmware de los componentes, o soporte lógico inalterable, es un programa muy básico, escrito a bajo nivel, y encargado de controlar la acción de los circuitos de un dispositivo (impresora, unidad óptica, teclado, disco duro,…). Dicho de otro modo, es una lógica primaria almacenada en una memoria tipo ROM que contiene una rutina de instrucciones que «les dice» a los circuitos cómo tienen que funcionar (cómo iniciar, qué operaciones realizar, establecer una interfaz de configuración para el sistema,…).

Generalmente, este código suele venir en chips de memoria PROM independiente (no siempre es así) de los chips controladores o de procesamiento. De esta forma, podrían actualizarse.

Diferncias entre firmware y controlador (driver)

firmware

Algunas personas confunden firmware con el controlador de un dispositivo, y es que puede ser algo muy parecido en cuanto a su definición. En cambio, no son lo mismo, y ambos trabajan conjuntamente de una forma muy estrecha.

No confundir controlador o driver (software), con controlador (hardware). Para más información, véase siguiente apartado.

La diferencia es que, aunque ambos hagan que un dispositivo funcione, el firmware va grabado en una memoria PROM en el dispositivo y el driver/controlador simplemente reside como parte del sistema operativo. Bien es cierto que se puede pensar que el controlador también se encuentra grabado en un chip de memoria, si se piensa en una unidad SSD. Pero, aún así, sigue habiendo una diferencia, y es que el disco duro es una unidad separada, mientras el chip de memoria PROM o flash del firmware está dentro del dispositivo en cuestión.

Visto de otro modo, si borras la información almacenada en el disco duro eliminas los controladores, pero eso no haría desaparecer jamás al firmware que está distribuido por cada uno de los componentes de la máquina.

Además, el firmware se encuentra en multitud de dispositivos y aparatos de todo tipo (vehículos, electrodomésticos, etc.), mientras que el controlador va siempre asociado a un equipo que tenga un sistema operativo.

Pero… para ponerlo más complicado, cada vez es más común que muchos fabricantes de hardware muevan su firmware directamente como parte del propio controlador y no esté alojado en una memoria en el propio dispositivo. Esto disipa las diferencias, pero se hace así para facilitar la actualización. ¿Desventaja? Que si desconectas el componente de hardware y lo usas en otro sistema no conservará la misma versión de firmware…

Además, en la actualidad, no es un gran problema albergar unos 64KB de código de firmware en un controlador. Eso supone un consumo de memoria casi despreciable, por lo que se adjunta al controlador y se inicia cuando el dispositivo se pone en marcha. Pese a eso, se sigue conociendo como firmware…

Diferencias entre controlador o driver y controlador de hardware

chip controlador
Chip Winbond Controlador E/S

También debes tener presente la diferencia entre el controlador o driver del sistema operativo y el controlador físico. El primero es un código a bajo nivel que se encargará de que un dispositivo de hardware funcione adecuadamente. El segundo es un chip que controla ciertas interfaces o dispositivos (USB, SATA, PCIe,…). Éstos últimos pueden estar montados en la PCB, o dentro de algunos SoCs, en tarjetas de expansión en el pasado, etc.

Nuevamente, ambos también trabajan muy íntimamente. Por ejemplo, cuando instalas los drivers USB en tu equipo, no estás instalando unos controladores para un componente específico, y aque se pueden conectar multitud de dispositivos USB en ese mismo puerto. Lo que estás haciendo es instalar el driver que ayudará a este chip que controla la E/S del puerto USB para que funcione.

Estos chips controladores actúan como enlace entre dos partes, como el controlador de memoria que administra el acceso a la memoria y con un dispositivo externo. A veces podría haber dos controladores a cada lado de un bus. Siendo el controlador del lado del host el controlador de host y el controlador del lado del periférico el controlador de periférico.

Ejemplos de este tipo de controladores pueden ser algunos MCU (Microcontroller Unit o microcontrolador) integrados en ciertos dispositivos, el controlador del teclado, el controlador de interrupción programable (PIC o Programmable Interrupt Controller), el chipset (northbridge y southbridge), chip UART, el controlador de memoria o MMU (Memory Management Unit), controladores DMA, controlador USB, controlador RAID, etc. Actualmente, con las mejoras en la integración, muchos de ellos se han integrado en un solo chip Super I/O, o dentro de la propia CPU (como es el caso del northbridge y la MMU).

¿Qué es el BIOS/UEFI?

BIOS UEFI
ROCKY-518HV – Atmel AT29C010A con Award BIOS

En los años 80s hubo un caos en cuanto a compatibilidad de los equipos informáticos, con varios estándares en la industria como Amiga, Apple, Atari, Acorn, etc. No todo fue negativo, ya que todos los jugadores implicados se vieron obligados a innovar y mejorar rápidamente frente a sus competidores para lograr fidelizar usuarios. Evidentemente, eso no permitía dominar el sector y monopolizarlo.

Esa tendencia pro-innovación se vería comprometida por la alianza Wintel. Es decir, una asociación entre Microsoft e Intel para posicionarse como la alternativa dominante del sector, implantando sus sistemas operativos y microprocesadores. Fue esto lo que hizo que ahora Windows domine, y también lo hagan los x86.

En aquel entonces IBM PC representaba solo una pequeña cuota de mercado de computación personal. Pero crecería rápidamente al publicar esquemas y documentación sobre las especificaciones para que terceros pudieran crear su hardware compatible. Junto con Wintel, que también pertenecía a este segmento, aquella reducida cuota terminaría por estrangular casi por completo el mercado.

Esto también repercutiría sobre la industria del software, ya que los desarrolladores comenzaron a mirar con buenos ojos esta fructífera plataforma, garantizando llegar a más usuarios con los mismos costes de desarrollo que si lo hicieran para otras plataformas menos dominantes.

En ese momento, otras empresas también fueron piezas clave de la historia. Empresas como Award, Phoenix, AMI Chips and Tecnologies, etc. Ellas comenzaron a crear chips con un firmware compatible con los IBM PC, facilitando que cualquier otro fabricante equipos pudiese hacerlos compatibles con el estándar.

Eso sería el principio del fin del IBM PC. IBM iría cediendo terreno frente a los PCs compatibles de firmas como Compaq, entre otras muchas. Sin embargo, el que no cedía era Microsoft, que ganaba importantes cantidades de dinero con su MS-DOS o por las licencias DOS concedidas a otras compañías. Intel ídem con sus microprocesadores o las regalías de otros (AMD, IDT, Cyrix,…) que diseñaban chips x86.

Ese firmware creado por esas compañías no era ni mas ni menos que el BIOS. Un acrónimo acuñado por Gary Kildall, apareciendo por primera vez en 1975 para sistemas CP/M que usaban una ROM para que el hardware pudiera arrancar el SO. Algo que adoptaron los DOS/Windows.

Como Microsoft ya dominaba, todos los fabricantes de equipos PC-compatibles se vieron obligados a dar soporte a los sistemas operativo de la compañía de Redmond. No hacerlo suponía operar en una cuota de mercado minoritaria.

Y esta es la historia por la que has tenido que tragar por mucho tiempo con el BIOS, con Windows, y con los chips x86…

BIOS

El BIOS (Basic Input Output System), o sistema de entrada y salida básico, es un código insertado en un chip de memoria flash o EEPROM de la placa base. Será el primer código que comienza a ejecutar el sistema cuando arranca, realizando una serie de comprobaciones de hardware y también localizando un medio de arranque al que transferirle el control, etc. Esas funciones básicas son:

  • Inicializar el hardware esencial para el arranque de la computadora. Para ello necesita una serie de controladores almacenados en la memoria no volátil que serán capaces de interactuar con ese hardware.
  • Realizar comprobaciones de hardware en un proceso conocido como POST (Power On Self Test). Una rutina que comprobará el estado de algunos componentes esenciales como la CPU, RAM, disco duro, etc., así como ciertos periféricos.
  • Tras la comprobación se encargará de buscar el sistema operativo para transferirle el control. Lo puede hacer en varios medios (disco duro, USB, unidad óptica…).
  • También aporta una interfaz de configuración llamada CMOS Setup. Allí se pueden realizar ajustes del hardware (ACPI, prioridad de los medios de arranque, RAID, activar/desactivar funciones o componentes,…). Para mantener esa configuración, y la hora del RTC mientras la computadora está apagada, se emplea una pila de la CMOS tipo CR2032. La duración dependerá de cada caso, pero puede ir desde los 2 a los 10 años. Cuando se agota, la fecha y hora se altera, además de perder la configuración y dejar la de por defecto.
pila BIOS
CR2032

UEFI

Actualmente, ese BIOS se ha sustituido por un sistema más moderno llamado UEFI (Universal Extensible Firmware Interface), que surgió inicialmente como el proyecto de código abierto Intel EFI (véase TianoCore), para más tarde transformarse en un estándar. Además de ser mucho más versátil, este nuevo sistema también aporta interfaces mucho más amigables para la configuración.

Me gustaría aclarar algo que confunde a muchos usuarios. Marcas como ASUS, MSI, Gigabyte, etc., no diseñan sus propios sistemas UEFI. Tras la absorción de Award por parte de Phoenix, y el cese de ésta también en cuanto al diseño de estos elementos, AMI se ha quedado en solitario. Las diferentes placas base usan AMI Aptio como base, solo que algunos fabricantes como ASUS, MSI o Gigabyte, agregan una capa UI en modo gráfico sobre Aptio. En esa UI ponen su marca, agregan gráficos y algunas modificaciones, pero bajo ellas está AMI. Otros fabricantes OEM (Dell, Lenovo, HP, Acer,…) suelen usar simplemente el menú por defecto de la Aptio, sin capas adicionales. Además, tanto en el caso de las marcas que añaden UI como en los que no lo hacen, son estas propias marcas las que ofrecen soporte y actualizaciones (y no directamente AMI).

Ambos son un tipo de firmware avanzado para hacer que los diferentes componentes funcionen adecuadamente, pero a nivel técnico son bastante diferentes. BIOS es un sistema primitivo de 1975, escrito en ASM/C, para el IBM PC, y fue necesario para iniciar componentes de muy diversos proveedores y lanzar el sistema operativo DOS.

Los modernos sistemas operativos también lo han tenido que heredar, hasta la llegada del UEFI. El firmware sucesor escrito en C y diseñado para los modernos computadores. Librándose del sistema obsoleto:

  • UEFI tiene una interfaz más moderna, e incluso permite el uso del ratón. La UI se puede poner en varios idiomas e incluso mostrar gráficos. BIOS usaba un menú basado en texto en el que simplemente se podía usar el teclado.
  • UEFI tiene capacidad de conexión a Internet para poderse actualizar, BIOS no (se debía hacer manualmente).
  • El código UEFI se ejecuta en 32/64-bit, mientras BIOS seguía haciéndose en 16-bit.
  • El arranque es más rápido en UEFI que en BIOS.
  • Mejoras de seguridad, como el polémico Secure Boot, para evitar bootkits o malware que se ejecuta en el arranque. Una solución que ha generado muchos problemas a otros sistemas operativos que no son de Microsoft, ya que para arrancar se necesitaban keys o firmas de Microsoft. De lo contrario, otros sistemas operativos eran detectados como si fuesen código malicioso y no permitían su arranque.
  • La UEFI tiene la capacidad de cargar cualquier memoria no volátil, siendo independiente del sistema operativo.
  • UEFI es modular y permite añadir extensiones de terceros para agregar nuevas funciones (overclocking, diagnóstico,…).
  • BIOS solo era compatible con tablas de particiones MBR, mientras UEFI usa GPT (aunque también podría usar MBR en modo Legacy). Eso permite eludir las limitaciones en cuanto a particiones del disco duro y capacidad total soportada. Con GPT se pueden crear hasta 128 particiones. Con MBR solo se pueden crear 4 particiones primarias, aunque se podía saltar la limitación con una partición extendida con particiones lógicas en su interior.
  • Tiene capacidad de emulación del BIOS (modo Legacy o CSM) para seguir siendo compatible con los sistemas operativos que solo eran compatibles con BIOS.
  • Capacidad de arrancar desde unidades de almacenamiento grandes. Mientras MBR solo soportaba hasta 2TB, en GPT se extiende hasta los 8 ZB.
  • UEFI es independiente de la arquitectura y controladores de la CPU. Por eso, puede adaptarse para usar ARM, RISC-V, etc. Y no solo ligada al mundo x86 como el BIOS.

Esta interfaz unificada de firmware extensible consta de varias etapas conocidas:

  • ¿…?: precediendo a la etapa SEC puede haber algún código binario que puede corresponder al microcódigo de la CPU, o a plataformas como Intel ME, AMD PSP, etc.
  • SEC (Security): primera fase que se ejecuta cuando se arranca el equipo, escrita en lenguaje ensamblador de la arquitectura a la que pertenece. Maneja todos los datos iniciales y puede pasar alguna información básica para la fase PEI. Esta rutina contiene el código necesario para iniciar la CPU con un estado de registros conocido.
  • PEI (Pre-Initialization): básicamente es un código de despacho para ir ejecutando una serie de módulos PEI. Después de la etapa anterior se invoca esta otra fase, cuyo objetivo es configurar la plataforma de hardware para dejarlo todo listo para ceder el control a DXE. Por ejemplo, inicia la memoria, la caché, deja los registros de hardware en un estado conocido o en un estado previo (en caso de suspensión), inicia y maneja operaciones ACPI, etc.
  • DXE (Driver eXecution Environment): código modular escrito en C y que implementa una fase durante la que se cargan los controladores que posee el firmware de los dispositivos o periféricos del equipo para comunicarse con ellos. Y, si es necesario, también monta discos, busca y ejecuta código de arranque del sistema operativo, etc. cuando se cargan los drivers o controladores de los dispositivos o periféricos del equipo. Tras DXE se transfiere el control al SO localizado…
    • BDS (Boot Device Select): pertenece a la etapa DXE. En esta parte, los buses de E/S, dispositivos E/S y los medios de arranque se inician. Los controladors de UEFI o las memorias ROM de los dispositivos PCI se ejecutan de acuerdo con la configuración del sistema y se procesan las opciones de arranque.
    • TSL (Transient System Load): etapa entre la selección del dispositivo de arranque seleccionado en el Setup y la transferncia del control al sistema operativo. En este puntos e puede ingresar en el shell EFI o ejecutar aplicaciones como el gestor de arranque el SO.
    • RT (RunTime): el UEFI finaliza y transfiere todo el control al kernel del sistema operativo, tras la ejecución de la llamada ExitBootServices().

En toda esta pila UEFI hay algunas partes que no son código abierto, por lo que son opacas. Algo que genera controversia, al igual que lo hace SecurBoot.

Alternativas

Libreboot, Coreboot, Linuxboot

Afortunadamente, existen alternativas al BIOS, como el EFI, el OpenFirmware de los PowerPC,  así como otros proyectos más recientes como CoreBoot, LinuxBoot, LibreBoot, etc. Por ejemplo, en el caso de CoreBoot, está orientado a sustituir el código propietario del firmware. Concretamente reemplaza las fases SEC y PEI. En el caso de LinuxBoot, viene a sustituir la fase DXE, además de aportar mayor velocidad y seguridad.

¿Qué es el microcódigo de la CPU?

AMD Am29k die shot

Una CPU tiene una unidad de control que será la encargada de interpretar las instrucciones que le llegan de memoria y poner a funcionar el resto de partes funcionales según la acción implícita en la instrucción. Por ejemplo, imagina una instrucción ADD de suma. La unidad de control la decodificaría y enviaría señales a la ALU a través del bus de control, para que ésta realice una suma entre dos datos.

Para que eso sea posible, se necesita algo (una capa de traducción) que haga a la unidad de control comprender todas las instrucciones, modos de direccionamiento, etc., de una ISA. Ese algo puede ser de dos tipos:

  • Cableada: son sencillas, usadas en CPUs del pasado o algunas actuales simples. Tiene la ventaja de ser mucho más eficiente y rápida, puesto que es una unidad lógica secuencial/combinacional que actúa en función de sus entradas para dar un resultado sobre sus salidas. Eso hace que no se puedan actualizar, y que sean menos flexibles.
  • Microprogramada: empleada en máquinas más complejas. Emplean lógica también, pero acompañada de una memoria no volátil donde se almacena un microcódigo. Ese microcódigo será accedido (consultado) para saber interpretar las instrucciones y determinar la acción a tomar. Al ser una memoria con un código, se pueden actualizar. Además, se puede subdividir en dos tipos:
    • Horizontal: los propios campos de bits almacenados en la memoria del microcódigo producen la señal de control y secuenciación (o solo necesitan una mínima codificación), sin necesidad de lógica combinacional intermedia como en el vertical. Eso hace que necesite una memoria más amplia en comparación con el vertical, con palabras que pueden tener 108 bits o más, pero es más rápido, permitiendo que en cada ciclo de reloj se pueda leer y decodificar una palabra del microcódico para controlar las unidades funcionales. Ejemplos de este tipo de codificación son los x86.
    • Vertical: cada microinstrucción está codificada de manera significativa. Los capos de bits almacenados en el microcódigo pasarán por una lógica combinacional intermedia que generará las señales de control y secuenciación para comandar las unidades funcionales de la CPU (registros, ALU, FPU,…). En consecuencia, necesita longitudes de instrucciones más pequeñas y menor espacio de almacenamiento para albergarlo, pero necesitará más tiempo de decodificación. Eso resultará en más ciclos de CPU. Ejemplos históricos han sido los IBM System/390, DEC Alpha (PALcode), IBM z/Architecture, etc.

Algunas modernas CPUs emplean este microcódigo para traducir cada microinstrucción en una/s operación/es muy sencilla/s llamada/s microoperaciones o μops. Por ejemplo, en un x86, verás decodificadores simples para aquellas microinstrucciones que son traducidas a una única μop, mientras que los complex se dedican a las microinstrucciones que necesitan de hasta 4 μops en algunos casos.

Ese microcódico es también un firmware muy especial y exclusivo de la CPU, básicamente un subconjunto del firmware de la máquina. Los fabricantes o diseñadores de los microprocesadores pueden lanzar así actualizaciones del microcódigo para cambiar el comportamiento a bajo nivel o mejorar la estabilidad y seguridad, sin necesidad de tener que sustituir el chip.

Para saber dónde está exactamente el microcódigo de una CPU, puedes ver donde se describe la unidad de control en este artículo. Además, deberías saber que ese área ROM del núcleo de la CPU no se modifica con las actualizaciones, es permanente. Siempre permanece inmutable desde la fabricación del chip. Esto es así puesto que la CPU es la encargada de ejecutar las instrucciones para la actualización de su propio microcódigo, no se podría eliminar o dejaría a la CPU inservible. Además, incluso cuando las actualizaciones de firmware fallan, la CPU sigue siendo suficiente funcional como para poder volver a una versión anterior. Sin embargo, la CPU puede contener una pequeña memoria volátil que permite la actualización del microcódigo incluso sin necesidad de ejecutar instrucciones para cargarlo. En los x86, esa memoria son registros llamados MSR (Model Specific Registers), y se emplean instrucciones específicas para leerlo (RDMSR) o para escribirlo (WRMSR). Lo que se escribe en ellos es la dirección de la región de memoria donde reside el nuevo microcódigo, para que así pueda usarlo sin tener que alterar la ROM.

Estas actualizaciones de microcódigo generalmente se envían como parte del firmware de la propia placa base, aunque el kernel Linux también tiene la capacidad de aplicar actualizaciones sobre este microcódigo y otro firmware. Para ello, Linux emplea tres métodos:

  • Carga temprana: actualiza el microcódigo durante el arranque, antes de la etapa initramfs. Es el preferido, y el que puede funcionar con CPUs con errores muy graves.
  • Carga tardía: la actualización se produce tras el arranque, algo que no es muy positivo en caso de que la CPU tenga problemas graves, ya que ya podría estar ejecutando un conjunto de instrucciones con errores. Lo positivo es que no necesita reiniciar.
  • Microcódigo incorporado: se puede compilar en el kernel, para que se instale con el el nuevo núcleo.

Independientemente de Linux, cualquier sistema puede cargar este microcódigo durante el arranque por parte del BIOS/UEFI (reside en una flash y es cargada en la CPU durante el arranque), o reemplazarlo más tarde desde el sistema operativo. El procedimiento de copia ya lo he explicado en una nota anterior…

¿Por qué es importante actualizar el firmware?

Intel errores y vulnerabilidades

El firmware, sea del tipo que sea, debe ser actualizado. Problemas en el firmware pueden hacer que un componente no funcione adecuadamente, o que no lo haga en absoluto. Una actualización también puede mejorar el rendimiento o las funciones, así como parchear vulnerabilidades que pueden ser explotadas y afectar gravemente a la seguridad del sistema.

Recuerdo hace años que mi regrabadora de CD/DVD dejó de funcionar repentinamente a consecuencia de un problema del firmware. Una vez actualizado, la unidad «resucitó».

En el caso de la CPU, los problemas de seguridad se han hecho especialmente importantes. Vulnerabilidades como Meltdown, o Spectre, y otras derivadas (side-channel attacks) han puesto en serios problemas a multitud de PCs domésticos y empresariales y, lo que es peor, a muchos centros de datos que manejan información crítica.

Este tipo de problemas necesitan de un rediseño de las microarquitecturas y buenas praxis para no cometer esos mismos errores. Pero una vez se dan, las actualizaciones del microcódigo pueden paliar dichas vulnerabilidades (no todas, algunas, como se ha podido comprobar, necesitan actualizar el microcódigo y también el kernel del sistema operativo, lo puede acarrear una reducción del rendimiento).

Me gustaría dedicar, en un futuro, un artículo especial sobre las vulnerabilidades del hardware, y sobre posibles soluciones.

Otros ejemplos de problemas históricos los encuentras en los chipsets, o los propios microprocesadores, también se han lanzado al mercado con algunos bugs de fábrica que han causado problemas serios de toda índole. Muchos de ellos se han solucionado también con la actualización del firmware, ya sea el de la placa base u otro.

En la próxima parte, el proceso de actualización

Isaac

Apasionado de la computación y la tecnología en general. Siempre intentando desaprender para apreHender.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

A %d blogueros les gusta esto:

Si continuas utilizando este sitio aceptas el uso de cookies. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar