Quantcast
Channel: Seguridad Agile
Viewing all 264 articles
Browse latest View live

Lidiando con protocolos legacy

$
0
0

Inspirado por un problema que suele ocurrir en ambientes legacy y en un artefacto que hallé hace muchos años tirado en la vereda, diseñaré una mitigación e intentaré implementar unos componentes, con la excusa de practicar qemu, networking, programar en C, cambiar el firmware de un router y finalmente FPGA.


En FTP las credenciales circulan en texto plano
En FTP las credenciales circulan en texto plano
 


El problema

 

Tenemos dos equipos, quizás en distintos datacenters, que están usando para intercambiar información sensible un protocolo inseguro como http, ftp o telnet. Estos protocolos son muy fáciles de inspeccionar si podés ver el tráfico. No se pueden cambiar por X motivo, esa es la esencia del legacy.

 

Inspiración

 

Cifrador de  X25
Cifrador de X25

El componente de la fotito lo encontré en la calle y se mete en el medio de una conexión serial para cifrar el canal, uno en cada extremo. En cierto modo es como agregar una capa que normalmente es lógica de modo físico. Está en mi lista de deseos en algún momento lograr la máxima posesión del mismo.

No sé los detalles de lo que hace, pero me imagino que cifra todo el tráfico y que lo hace de modo transparente, los nodos que se comunican no se enteran de este proceso. La diferencia con mi proyecto es que se tratará sólo un tipo de tráfico y el resto circulará sin modificaciones.

 

Análisis de impacto

 

Hay varios inconvenientes: un atacante puede ver usuario y credencial si puede inspeccionar el tráfico de red. Luego, como puede ver todo el tráfico la información sensible que haya.


En términos de CVSS, como vulnerabilidad, si dejamos de lado la integridad el valor pasa de 6.5 a 4.6 

 

Adyacente sin integridad
Adyacente sin integridad


Physical sin integridad
Physical sin integridad


Si consideramos la integridad, de 8.16.1  


Adyacente con integridad
Adyacente con integridad


 

Physical con integridad
Physical con integridad


Esta mejoría se debe a que hace falta ir físicamente al datacenter y pinchar el cable o sacar componentes, no se puede atacar desde otra máquina conectada a la misma red. 

Fijate que no cambie de Adyacente a Físico en la puntuación base, pues ese es el valor de vulnerabilidad en general, lo hice en la puntuación de entorno, es la aplicación concreta de las circunstancias a la base.

 

Mitigaciones

 

El cable cruzado


Una solución sencilla si estuvieran juntos y se pudiese agregar una placa de red en cada equipo es usar un cable cruzado.

 

Networking


Si no se puede tirar un cable o agregar placas, se podría hacer a nivel del equipamiento de red, cosa que no sé hacer, no tengo equipamiento de red. Me imagino algo así como "si viene de tal IP y va a tal IP y es de tal Protocolo, enviar por algún modo tal que no sea muy visible, ya sea una vlan o mejor cifrado.

 

Componentes como el de la fotito


Puedo desarrollar un par de dispositivos que separen el tráfico, algo así:

 

            +-----------------+           +----------------+
+-------+   |                 tráfico común                |  +-------+
|sistema|<--------------------------------------------------->|sistema|
+-------+   |+--------------+ |           |+--------------+|  +-------+
            ||tráfico legacy|<--cifrado-->||tráfico legacy||
            |+--------------+ |           |+--------------+|
            +-----------------+           +----------------+

 

Si el tráfico no corresponde, pasarlo de una interfaz a la otra sin más trámite.

Si el tráfico corresponde, tratarlo de alguna manera  y pasarlo al otro componente, que invierte el tratamiento y se lo dá al destino.

 

Modo de protección


Veo dos maneras de implementar la protección:

 

Tunneling

 

Este es el modo más sensato, usar la magia de iptables/fwbuilder y establecer una VPN para hacer circular el tráfico de interés por ahi.

 

Cifrado por paquete

 

No sé casi nada de criptografía, así que no tomés como referencia mi diseño ni implementación.

En terminos de latencia, lo mejor que podría hacer es un xor del tamaño del buffer, pero tendría que ir cambiando ese xor para cada paquete, pues si se repitiera se abriría la puerta a sencillos ataques.

 

Ponele que cifro con el mismo k varios mensajes:

a       01011011 
k       01010101  
A       00001110

b       00110011
k       01010101
B       01100110



Como atacante, tengo todos los A,B...


Supongamos que tengo un a, debido a que por lo general el primer mensaje suele ser igual debido a encabezados, por ejemplo una página web suele comenzar con


<!DOCTYPE html>
<html

Fijate como obtengo el mensaje b, o cualquier otro, teniendo un solo mensaje conocido:



A       00001110
B       01100110
xor     01101000

a       01011011 
b       ????????
xor     01101000

b       00110011

 

Y este es un ataque increiblemente sencillo, casi el único que estoy en condiciones de explicarte, no sos vos, soy yo. Después hay mil maneras sutiles de fallar. Repito, lo que haga es de juguete.


Cuando llegue el momento, veremos...

 

Implementaciones


Hay varias maneras que se me ocurren y pienso intentar implementar apuntando al máximo aprendizaje.

 

Virtualización


Puedo usar Qemu o VirtualBox

  • Ventajas
    • gratis
    • homogéneo
    • ambos modos
  • Desventajas
    • aburrido
    • poco creible

 

Pese a lo aburrido y poco creible, va a ser lo primero que haga, usando ambos modos, como para comprobar que se puede hacer y estar atento a que no haya algún bloqueante que luego va a ser más difícil de identificar. Además usaré qemu pues tengo poca práctica últimamente

 

Computadoras


Dos viejas netbooks y un adaptador usb-ethernet

  • Ventajas
    • más creible
    • homogéneo
    • ambos modos
  • Desventajas
    • tengo que comprar otro adaptador usb-ethernet o mejor dos para que sean usb 3 y gigabit, unos u$s 40
    • ocupa mucho lugar y consumo
    • sigue siendo aburrido

 

Como no le veo mucha diferencia a virtualizar y me obliga a comprar el adaptador y principalmente sigue siendo aburridísimo, no lo voy a implementar.

 

Routers


Un router hogareño de más, otro que tiene sólo un ethernet, pero puedo usar el adaptador usb pues tiene usb

  • Ventajas
    • gratis
    • divertido
    • ambos modos
    • por fin le doy uso a esos routers
    • tengo que cambiar el firmware
  • Desventajas
    • heterogéneo
    • son distintos
    • tengo que cambiar el firmware

 

Esta implementación sólo la haré por que me obliga a cambiar el firmware, cosa que nunca he hecho. Probablemente me conforme con el modo tunneling.

 

FPGA


Usar dos FPGA con dos o cuatro pmods ethernet

  • Ventajas
    • máxima diversión
    • máxima dificultad
    • máximo aprendizaje
    • heterogeno, tengo que usar dos placas distintas pues es lo que tengo
  • Desventajas
    • heterogeno, tengo que usar dos placas distintas pues es lo que tengo
    • al menos u$s 80 mas impuestos y gastos de envío
    • sólo cifrado
    • quizás no me dé el cerebro para hacerlo

 

 

Resumiendo

 


TunnelingCifradoLo haré?
Virtualessisiambos
CompussisiNo
Routerssinotunneling
FPGAsnosicifrado


Dame unos meses, pues ahora estoy medio complicado.






H4kc3d 2020: the missing pieces

$
0
0

 

Otro año de H4ck3D


Aunque no es la primera vez que doy una charla virtual, pues ya he dado varias en el trabajo, es la primera ante tanta gente tan desconocida. Por más que Javier y Fabián (los organizadores) confían en que aunque yo pase vergüenza por todos los errores que cometo ellos no por que quizás de algún modo logro darle una cierta cohesión y claridad, a veces sospecho que les gusta más que lo técnico lo "artístico", no sé, pero suficiente de estas intangibilidades.

Mirando el video, la presentación que tenía y lo que hay en mi mente, no puedo dejar de notar que algunas cosas me faltaron decir o recalcar.

 

La charla


La apertura fue mostrar las diferencias entre software y hardware por un lado y entre el error y la mala intención por el otro.

 

La idea perdida

Es extremadamente difícil desde el software detectar o prevenir cualquiera de estos ataques, listo, lo dije. Era lo que venía a continuación de la cadena de confianza.


Las fallas

 

En comparación a otras charlas, podríamos decir esta ha sido de las mejores, pues es de las más complicadas y con un sólo error técnico, que en la demo del bit supervisor no se vió como se cargaba el capacitor en el osciloscopio, calculo que no había seleccionado el canal apropiado, hubiese sido tán fácil apretar un botoncito... pero en "modo demo" he llegado a la conclusión de que es mejor no tocar nada, no vaya a ser que se rompa lo siguiente. Está bueno intentar acordarse al final y ahí experimentar.

Tampoco expliqué nada de ese circuito, como que se me vino encima el poco tiempo que quedaba.

 

Las demos


Quería hacer un montón de demos, pero justo los tres meses previos han sido terribles, sólo pude hacer dos decentes.

 

Supervisor

 

Se trata de poder cambiar el bit de supervisor mediante un circuito auxiliar que detecta una anomalía en la frecuencia de uso de ciertas pistas. En el caso del ejemplo se trata del bit más alto de las instrucciones. Los detalles completos los iré publicando a medida que tenga tiempo. Te puedo adelantar los dos videos, en el primero, vemos el comportamiento normal:

 




En el segundo, con el bichito activo.





Acelerador criptográfico troyanizado

 

Las explicaciones completas están en estos artículos:


No hay video, pues la terminé a la 1:am del día de la charla, fuí sin red de seguridad.

 

Fuga de información por VGA

 

De esto tambien haré un artículo pronto, sólo mostré un video y no lo he implementado en hardware aún. El resumen es que como hay tiempos muertos en la transmisión de la señal VGA de la placa a la pantalla, se puede aprovechar para insertar información ahí. Este es el video de la simulación:

 


El código de las demos:


  • https://github.com/cpantel/HardwareMalwareAccelerator
  • https://github.com/cpantel/HardwareMalwareSupervisor

 

y en algún momento 

  • HardwareMalwareLinuxReset
  • VGALeak



Todos los videos de todas las charlas en:


  • https://www.youtube.com/watch?v=D5btBXAcEec (minuto 15 aprox.)
  • https://www.youtube.com/watch?v=dVXJvWRWl5o
  • https://www.youtube.com/watch?v=CtljkKeirtk

Forzando Brutalmente MD5 - parte 6 - FPGA

$
0
0
¿Venís de leer la intro, la parte 1, la parte 2, la parte 3 la parte 4 y la parte 5?

El tema

Habiendo agotado en lo que a mi respecta las maneras de calcular MD5 usando una o varias CPU, ya sean sus instrucciones básicas o extendidas, habiendo aplicado una optimización llamada "loop unroll", que consiste en tomar un loop, quitarle el contador y escribir su cuerpo tantas veces como hubiese sido ejecutado, adaptando cada iteración a los valores que hubiese recibido del contador, llegó el momento de no usar más CPU.


Fijate que más arriba le dediqué mucho al loop unroll. Es que desde el primer día que decidí encarar este proyecto, sabía que era lo que en última instancia iba a utilizar.

Todo el caminito que recorrí por las CPUs, aunque muy divertido e instructivo, realmente aprendí mucho, asenté, fundamenté y completé mucho conocimiento, no era para mi, era para vos.

Lo que yo quería hacer desde el comienzo era esto, implementar el forzador de MD5 en una FPGA, pero si vos no sabés nada de técnicas digitales, ni cómo funcionan la computadoras, ni assembly, ni C, ni programar quizás, te muestro esto primero y te mato.

En el trabajo fui mostrando cada etapa en una charlas a gente de diverso conocimiento técnico y apuesto que de no haber seguido este camino, a la mayoría ahora le costaría asimilar algo de todo esto, no habría ninguna conexión con su conocimiento.

 

FPGA

Ni instrucciones básicas, ni extendidas, ni multithread/multiprocess, ni optimizaciones del compilador, nada.

Había comentado antes que la velocidad del clock se había convertido en un limitante y eso había impulsado el paralelismo del multicore.

Tambien que en el caso de supercomputadoras como Epiphany y GPGPU, que esos cores fueran lo más sencillos posibles para ahorra silicio y poner más cores.

Aondando en esa tendencia, pensá que un core es una CPU de propósito más o menos general y aunque sea de propósito muy específico, cada problema que resuelvas no va a utilizar buena parte de los recursos que ofrezca.

Si además, es muy especifica y el problema cambia, no la vas a poder utilizar.

Si pudieras reconfigurar el hardware para que el silicio existente esté íntegramente dedicado a la resolución del problema que estás encarando, alcanzarías el máximo rendimiento.


El hardware reconfigurable se llama FPGA y se programa principalmente en VHDL como en este caso y Verilog.


Pipeline
Pipeline

La idea es que con un contador vas generando las claves candidatas y le vas a aplicando algo así como el loop unroll que habíamos visto antes, pero con la diferencia que cada etapa, cada ronda es un circuito que está ejecutando las operaciones en simultáneo con las demas. 

Durante los primeros 63 clicks del reloj el comparador recibe basura, de ahí en más lo que había en el contador hace 64 ticks.

De esta manera tenemos un paralelismo de 64, así como con AVX2 8, con GPU varios centenares y con multicore x 32.

La ventaja abismal, es que en cada tick se obtiene un hash entero, a diferencia de CPU/GPU que lleva muchísimimos ticks, al punto de que el clock de la FPGA que tengo es de sólo 100Mhz y aún así, como tengo espacio suficiente en la FPGA para instanciar hasta 10 pipelines, alcanza a la GPGPU, consumiendo mucho menos.

Si además este diseño lo ajustar para poder pasarlo a un ASIC, esto es un chip no reconfigurable, carísimo para un sólo ejemplar pero baratísimo por millón, podría aumentar la velocidad de clock y agregar instancias del pipeline, pues FPGA ocupa mucho espacio por ser reconfigurable.

Según he leido, ese cambio lo haría 10 veces más rápido por el clock y supongo que otras 10 veces más rápido por poner más instancias. De hecho, para minar bitcoins existen ASICs.

El camino


Tuve que tomar diversos caminos, divergente, simultáneos e incluso superpuestos debido en parte a mi desorden mental, en parte a mis conocimientos limitados, al tiempo disponible, al hardware disponible y a las dificultades de los entornos de desarrollo.

Una vez que tuve una versión que malamente funcionaba, le quité todo lo superfluo y lo instancié varias veces en mi hardware para ver cual era el rendimiento máximo.

Utilicé la placa Nexys4-DDR que entre que la pedí y antes de llegar ya me quedó obsoleta, mala suerte. Es una FPGA de las más caras de las baratas o más baratas de las caras, tiene VGA, switches, botones, 7 segmentos, audio, usb, de todos.

Más arriba mencioné el loop unroll como gran protagonista. Es que de no utilizarlo, tendría que diseñar una circuitería de control que comenzaría a parecerse a una CPU, perdiendo las ventajas ganadas.

De todos modos, esa proto CPU tendría sólo las instrucciones necesarias para este problema.






cpucpu
unroll
avx2
+ unroll
threads
x 4
+ avx2
threads
x 32
gpu
fpga
x 1
fpga
x 8
fpga
x 10
velocidad5.79.647.9153.41791090.11008001000
rendimiento watt0.861.447.1923.013.1106.6445360450
rendimiento dolar2.38419.9663.9213.16454.2178.13625781.25






cpucpu
unroll
avx2
+ unroll
threads
x 4
+ avx2
threads
x 32
gpu
fpga
x 1
fpga
x 8
fpga
x 10


5.79.647.9153.41791090.11008001000
cpu5.71.001.688.4026.9131.40191.2517.54140.35175.44
cpu
unroll
9.6
1.004.9915.9818.65113.5510.4283.33104.17
avx2
+ unroll
47.9

1.003.203.7422.762.0916.7020.88
threads
x 4
+ avx2
153.4


1.001.177.110.655.226.52
threads
x 32
179



1.006.090.564.475.59
gpu
1090.1




1.000.090.730.92
fpga
x 1
100





1.008.0010.00
fpga
x 8
800






1.001.25

 

Con 8 pipelines, como corre a 100Mhz, tenemos 800 de velocidad, no muy lejos de los 1090 de la GPU. Aunque no lo hice funcionar pues se me complica la lógica, podría tener 10 pipelines y estoy seguro que de tener un poco más de praćtica y aprovechando los DSPs podria llega a meter 11 o incluso 12.



nexys4ddrparallellaPYNQ-Z2


artix-7zynq 7010zynq 7020

luts15k25k85k

dsp24080220
pipelines
implementados
o implementables
81345
máximo
estimado
111447


Utilizando sólo los luts y dsp disponibles, proyecto los números para las otras dos placas que tengo. No estoy considerando que quizás podría subir la velocidad del clock por encima de 100Mhz. Para ello tendría que usar los PLLs disponibles y evaluar los timings a ver si llegan a hacerse las operaciones a tiempo.

Con respecto a los DSP, supongo que no haría un pipeline de DSPs si no que una etapa de cada pipeline estaría implementada así, futuro improbable.

Si juntara todo, tendría entonces entre 6600M y 7200M hashes por segundo y 1090 con la GPU. Luego, tendría que pedirle a alguien que tenga una GPU decente que ejecute mi programa, pues mi GPU es GeForce 940MX, al momento de hacer este análisis, 2019, un GeForce GTX 1080 Ti era casi 9 veces más veloz según algún benchmark que no registré.


Al momento de escribir esto, GeForce RTX 2080 Ti sale u$s 1000, el doble que las tres FPGA que tengo y consume 250 Watts vs los menos de 15 Watts que consumen las tres juntas, pero, si se puede proyectar la comparación de mi GPU, tendría una velocidad de 15000M, así que el rendimiento dolar sería apenas mejor para GPU y el energético 15 veces mejor para las FPGA, pero tomalo con pinzas.

No sé cuántos LUTs se consiguen por u$s 1000.

De todos modos, todo esto es para MD5, habría que ver que pasa con algoritmos modernos tipo SHAx.

 

Código

  • https://github.com/cpantel/Forzando-Brutalmente-MD5/tree/master/v8_fpga

Curso Security AWS

$
0
0

Nuevamente, gracias al trabajo, he recibido capacitación de AWS, en este caso Seguridad.

Cloudshell
El lunes esto no estaba


Estas son unas notas un tanto inconexas tomadas y deducidas durante el curso que me pueden servir en el futuro para intentar certificar una vez haya ganado alguna experiencia práctica. Claramente una certificación no debería obtenerse por estudiar, eso es un curso o materia, una certificación es la medición de tu conocimiento por lo que has hecho, prefiero no repetirme.

Tené en cuenta que lo que sigue es mi visión, no necesariamente la de AWS así que no lo tomes como referencia para tu certificación.

Me resisto a hacer una enumeración de los servicios tratados y sus relaciones, en cierto modo sería un leak pues parece no estar publicado y no tengo ganas de estar pidiendo permiso a AWS.
 

La previa

No había visto que entre las precondiciones, además de Architecting on AWS que ya había hecho, estaba AWS Security Fundamentals o AWS Security Essentials, así que entré un poco rengo.

Es más, tenía un plan de tomar algunos cursitos tanto de AWS como de qwiklabs como de LinkedIn Formation pero no los hice para llegar sabiendo lo justo, dada la duración del curso cuando menos supiera previamente mejor, pues en las partes que ya sé me puedo dispersar, por ejemplo CIA y STRIDE, con el riesgo de perderme el momento en el cual sale de lo que ya sé.

El sonido


En el curso anterior tras un ratito dejaba de funcionarme el mic, que se arregló actualizando el chrome, no me había dado cuenta de que estaba con una versión muy vieja.

El docente



El docente muy ok, pobre, entre la interfaz y lo que tenía preparado habían pequeñas diferencias, es que AWS cambia bastante rápido, incluso en el medio del curso apareció una nueva funcionalidad o al menos el acceso, CloudShell, abrir una consola desde el menu.


Sólo tuve un desacuerdo, que intentaré desarrollar en otra entrada pues me requiere bastante pensamiento, investigación y pruebas.

El curso


El curso no es de técnicas, como puede ser pentesting, si no comprender las herramientas y servicios relacionados, sus configuraciones y buenas prácticas.

Al igual que con los cursos de Akamai Site Defender y Bot Defender, hay una buena parte del aprendizaje que consiste en traducir lo que ya sabés de la vida al lenguaje local.

Los talleres son copiar y pegar, yo intenté escribir los comandos para ir fijándolos.


Las notas



Responsabilidad


AWS tiene un modelo que llaman "shared responsability", responsabilidad compartida, que básicamente se reduce a que si el servicio es gestionado es responsabilidad de AWS, si no es tuya


Por ejemplo, para una base de datos, en todos los casos, la seguridad del dato es tuya, pero respecto a la infraestructura:

  • Usar un servidor instalado en una EC2
    • toda tuya
  • Usar RDS
    • la actualización y parcheo queda a tu cargo
    • la infraestructura subyacente AWS
  • Usar DynamoDB
    • todo (menos los datos ya dije) es AWS

 

Pentesting


Hay servicios que no requieren autorización de AWS para hacerles pentesting.

Sobre cualquier otro, hay que abrir un ticket, en caso contrario se considera un ataque y aws reacciona acordemente.

Este ticket incluso puede otorgarte ayuda de soporte para hacer la prueba.

Cualquier incidente puede generar un contacto desde el soporte de AWS el cual es fundamental responder y reaccionar a la brevedad pues puede llegar a generar un bloqueo de la cuenta y acciones sobre los servicios afectados y puede llegar a generar incluso problemas legales.


Forense


Para análisis forense se debe "desconectar" el equipo, tomar una imagen, no vimos el detalle, conectar a una VPC ya preparada para forense. O bajar la imagen y procesarla on-premise


Temas sueltos llamativos


Me resultó muy simpático un indicador de anomalía, billing activity, sigue el rastro del dinero.


Interesante, el tema de multifactor con acceso programático, me enteré que algunos proveedores tienen una API, yo pondría un cámara con OCR a un token físico, jaja.

Hardware Malware: bit supervisor

$
0
0

 

 

La idea de esta demo está basada en un paper que no recuerdo si he leido en su completitud o no. Si no lo he leido ha sido a propósito, pues una vez comprendida la idea central, no quería spoilearme cómo hacerlo.

Repasemos: hay que instalar subrepticiamente en el proceso de diseño y  construcción de un chip antes de que llegue al silicio, un mínima lógica activada por las órdenes legítimas o por un capacitor que se carga cuando hay mucho tráfico en una pista donde habitualmente hay poco.

 

Activación
Activación


O sea, normalmente el capacitor se está descargando, pero si hay una sucesión suficientemente sostenida en el tiempo tal que la carga supere  a la descarga y llegue al punto tal que su valor represente un 1 lógico, la mínima lógica prenderá el bit supervisor.

¿Qué es el bit supervisor? El que permite proteger a nivel de hardware recursos como la memoria, IO y ciertas instrucciones y separar los procesos del usuario común del sistema operativo

Esto va desde el simple deseo de que las cosas funcionen bien, como que un programa no pise la memoria de otro hasta la seguridad del sistema, donde un programa no puede ver la memoria de otro.

 

Tenía varios caminos, del cual implementar el ataque como en el paper con un ASIC quedaba completamente fuera de mi alcance.

La siguiente posibilidad era obtener el VHDL o Verilog de una CPU, por ejemplo 6809 o 68000, teniendo que cumplir con las siguiente condiciones:

  • implemente bit supervisor: obvio.
  • la pueda hacer funcionar con sencillez: para mi nada es sencillo.
  • entienda yo cómo se interactúa con el bit supervisor
  • pudiera yo encontrar el punto donde colocar el capacitor

Comprenderás que el capacitor debe ser externo, con VHDL o Verilog lo único que puedo hacer es agregar un contador, lo cual pierde toda la gracia.

A esto se le suma que tengo que aprender una parte del lenguaje de máquina de esa CPU y como hacerla arrancar, probablemente canibalizando un programa existente... demasiado. Esas son todas super capacidades que no tengo o no puedo adquirir en un tiempo razonable y, ¿quién quiere dedicar meses de su vida para aprender a usar una arquitectura obsoleta hace décadas?

No voy a mentir, yo querría, pero prefiero desperdiciar mis recursos en otras cosas igualmente improductivas pero más interesantes.


Hasta acá es lo que expuse en la charla de H4CK3D 2020, pero por falta de tiempo no entré en algunos detalles jugosos del diseño de la demo.

El camino más fácil y bastante productivo en términos educativos es hacerme mi propia CPU, tal que implemente lo mínimo necesario para la POC. Tuve que pensar el programa más corto posible que sirva y sólo implementar esas instrucciones.

Necesito:

  • Una operación que Output que sólo funcione cuando está el bit supervisor prendido (out).
  • Una operación tipo SVC (Super Visor Call), para pasar al modo supervisor (svc).
  • Una operación de retorno de SVC, para retomar el programa y salir del modo supervisor (ret)
  • Una operación para cargar un valor en el único registro (set)
  • Una operación de salto condicional para poder hacer un loop. (jnz)
  • Una operación de incremento para poder hacer un loop (inc)

Para logra la máxima sencillez, en los MSBits puse el opcode y en los LSBbits el operando de haberlo. Todas instrucciones de un byte. El Program Counter arranca en 16 debido a una evolución que no vale la pena que muestre.

Tanto el inc (1000xxxx) como el nop (1001xxxx), tienen el MSB observado por el capacitor.

La SVC tiene hardcodeada una dirección a la cual saltar, donde reside el código con priviliegios, no se si ha existido alguna arquitectura tan primitiva como la mía en ese aspecto, pero no olvidemos que esto tiene otro objetivo, no es el estudio de arquitecturas de microprocesadores.

El programa de ejemplo, en verde el funcionamiento legítimo, en rojo se bloquea la operación por falta de privilegios, en amarillo el ataque y en aqua la explotación.

Código usuario

  16: h90;  // nopC 17: h90;  // nop  
  18: h90;  // nop
  19: h90;  // nop
  20: h90;  // nop
  21: h90;  // nop
  22: h25;  // set   0101 en registro
  23: h40;  // svc   0101 en leds
  24: h2A;  // set   1010 en registro
  25: h40;  // svc   1010 en leds
  26: h2F;  // set   1111 en registro
  27: h40;  // svc   1111 en leds
  28: h25;  // set   0101 en registro
  29: h30;  // out   falla
  30: h2A;  // set   1010 en registro
  31: h30;  // out   falla
  32: h2F;  // set   1111 en registro
  33: h30;  // out   falla
  34: h20;  // set   Este es setup del loop
  35: h80;  // inc   incremento del registro
                    
inicio del loop
  36: h90;  // nop   nada
  37: h1F;  // jnz   salta al inicio del loop
  38: h25;  // set   0101 en registro
  39: h30;  // out   0101 en leds
  40: h2A;  // set   1010 en registro
  41: h30;  // out   1010 en leds
  42: h2F;  // set   1111 en registro
  43: h30;  // out   1111 en leds
  44: h90;  // nop
  45: h70;  // hlt

código privilegiado


  46: data = 8'h30;  // out legítimo
  47: data = 8'h00;  // ret


Si tuvieras ganas de mirar el repo  en la carpeta javascript podrías apreciar la evolución desde una simulación más abstracta a una más concreta considerando la microarquitectura, completamente en vano pues a la hora de implementar en Verilog usé la primera.

Si tuvieras ganas de mirar el Verilog verías el comportamiento legítimo del bit supervisor en svc y ret como se prende y apaga:

OPCODE_SVC: begin
  supervisor = 1;
  error= 0;
end

OPCODE_RET: begin
  supervisor = 0;
end

Luego, en out, si el bit está prendido transfiere el registro al puerto de salida, si está apagado tirar error:

OPCODE_OUT: begin
  if (supervisor) begin
    gpio = A[3:0];
  end else begin
    error = 1;   
  end
end

 

El malware lo podemos ver  en la interfaz de board.v

  output malware_activation_signal_out
  input  malware_activation_signal_in

que son los cables que van y vienen del capactor.

Luego en la implementación:

   assign malware_activation_signal_out =
           cpu.opcode[3] ? 1 : 1'bz;

dice que si el MSB del opcode es 1 ponga un 1 y si no ponga en alta impedancia para que no se descargue tan rápido el capacitor. Sabiendo más electrónica seguramente se puede reemplazar la condición por un diodo.

Finalmente, en cpu.v

OPCODE_NOP: begin
  if ( board.malware_switch &&
      (  board.malware_input ||
         board.malware_activation_signal_in
      ) )
     supervisor = 1;
end

Lo que dice es que si está habilitado el malware y ya sea porque está activado por un switch o por el capacitor, prenda el bit supervisor.

Mi conocimiento de electrónica analógica es ínfimo, así que prefiero no explicar mucho, en parte por vergüenza, en parte para no brindar conocimiento erróneo.

 



El capacitor que usé es gigante por los tiempos de un clock tal que se pueda apreciar en una demo. En la realidad sería minúsculo.

 

El PMOD con los leds y el bichito
El PMOD con los leds y el bichito

 

El potenciómetro está para calibrar los tiempos de descarga. Con respecto al PMOD explico un poquito en otra entrada.



 





Para trabajar más cómodo y aprovechar varias máquinas

$
0
0

Tengo una máquina que es muy cómoda pero no debo usarla para el trabajo. La del trabajo es más potente pero inusable, ¿qué hago?

Pues uso las dos, tomando lo mejor de cada una.

Objetivos


Ejecutar las aplicaciones sensibles y/o de alto consumo de CPU en la Máquina Remota operando desde la Máquina Local para aprovechar sus múltiples monitores y mejores teclado y mouse.

Mantener toda la información de trabajo a la Máquina Remota.

 

Detalles

  • Máquina Remota
    • más segura
    • más procesador
    • bastante memoria
    • dificultad para usabilidad
      • display
        • 1920x1080
        • casi 14 pulgadas (35 cm) diagonal
      • mousepad
      • teclado membrana
  • Máquina Local
    • no necesariamente segura
    • con menos procesador
    • el doble de bastante memoria
    • usabilidad óptima
      • display
        • tres monitores
        • 1920x1080
        • 23.5 pulgadas (60 cm) diagonal
      • mouse común
      • teclado IBM Model M 1987



Las aplicaciones son un browser y varias máquinas virtuales. Dentro de esas virtuales, un completo zoológico de browsers, terminales, dockers, mongos...

Estoy usando Linux Mint tanto en una como otra máquina, no deberías necesitar cambiar mucho con otras distribuciones. Las virtuales son agnósticas siempre que puedas controlar la resolución.


Comienzo confesando que lo del browser ni probé mucho pues se achanca mucho el display y además necesito hacer video conferencia, lo que implica lidiar con la cámara, micrófono y audio, quedará para otra ocasión, en esta entrada sólo desarrollaré la configuración de las virtuales y un mínimo soporte para el intercambio de archivos consftp  y otro mínimo nivel de interacción con ssh -X, centrándome en los displays y las virtuales.


Memoria


Aunque es verdad que la Máquina Local tiene el doble de memoria, lo que siempre me termina matando es el browser, no las virtuales.


Red


Esto no lo hice hace meses pues estaba sin switch, mi hub de 10 no es suficiente para la conexión necesaria. No probé si por WiFi alcanza el ancho de banda.

A cada máquina virtual hay que ponerle la interfaz en modo "bridge" para que tenga una IP alcanzable por la Máquina Local por si querés hacer ssh/sftp. Además, en View hay que activar "Remote Display". Recordá que la IP es la de la Máquina Remota, no la de la virtual, cada virtual está en un puerto distinto que se debe setear al habilitar el Remote Display.

 

Lo más prolijo sería fijar la dirección IP de la Máquina Remota para no tener que estar pescándola todos los días... veré, igual es extremadamente fácil. 

Si tuviera una red de 1000...

Display



Acordemos algunos nombres:

Una pantalla es... una pantalla.

Un workspace es como una extensión virtual del escritorio, un duplicador, triplicador, multiplicador de pantallas. Se puede pasar de uno a otro mediante una combinación de teclas o con el "Workspace Switcher"

La configuración de los workspaces es muy personal, esta es la mía:

 
En la Máquina Local tengo seis workspaces, en uno de ellos Remmina con los RDPs a las virtuales.

En la Máquina Remota y en cada virtual cuatro workspaces por costumbre.

Esto hace que tenga hasta 18 + 4 + 4n workspaces, no me va a hacer muy bien


Resoluciones


Tras bastante pelear llegué a este procedimiento para hallar la configuración óptima:

  • Medir la pantalla local (1920x1080)
  • Darle a la virtual en la Máquina Remota esa resolución, aunque sobre o falte, si no la vas a usar ahí, no hace diferencia.
  • Le pedís a Remmina "Full Screen" y "Resize the window to fit in remote resolution"
  • Eso me ocupa una pantalla entera, ok


Problemas, siempre hay problemas, como uso el mejor workspace y es donde está la barra de comandos, no puedo pasar a otro workspace sin usar

Control-Alt-(left/right) Arrow


Si necesitás salir de Full Screen y no encontrás el panelcito, la combinación de teclas en Remmina es:

Right-Control-f

 

Si tenés varias conexiones a varias virtuales, podés pasar de una a otra con:

 

Right-Control-(left/right) Arrow


Navegación
Navegación


Me molesta que no he logrado que Remina me muestre dos conexiones en paralelo, lo cuál es útil cuando una operación abarca varias virtuales.


Power Management


En la Máquina Remota el display se puede ir a dormir sin problemas, a menos que quieras tener esa pantalla extra para ver notificaciones. Mejor no dejés que la CPU se duerma.


Virtual Box

Te conviene arrancar en modo headless, así podés arrancarla vía ssh -X desde la Máquina Local, lo que sea para no mover el trasero.



Topología
Topología

 

Intercambio de información



Es un poco tedioso, hay que hacer una carpeta compartida a las virtuales, probablemente siempre la misma. Esto implica instalar las "Guest Additions". Entonces si recibo por mail un archivo al cual tengo que hacerle un proceso, el caminito es:

mail con datos
     ( Bajar a )
Máquina Local / Downloads
      (copiar a)
Máquina Remota / Shared
      (Abrir desde)
la virtual apropiada
      (salvar a)
Máquina Remota / Shared
      (copiar a)
Máquina Local / Downloads
      (enviar como)
mail


Lo voy a usar un tiempo y veré si hay alguna mejora para compartir.


Deudas

  • Ver como marcha la memoria.
  • Usar el browser remoto.
  • Aumentar los colores de 256 a algo mejorcito.
  • Probar WiFi.
  • Fijar IP.
  • Ver comportamiento ante CPU sleep.
  • Investigar como separar sesiones de Remmina o cambiar de cliente.

Forzando Brutalmente MD5 - parte 7 - caminos no tomados

$
0
0

¿Venís de leer la intro, la parte 1, la parte 2, la parte 3, la parte 4, la parte 5, la  implementación FPGA en nexys4ddr y la parte 6?

Dejo registradas acá todas las ideas y caminos no explorados, ya sea por falta de tiempo, ganas, dinero, interés o acceso.


No garantizo que sea la última, pues me falta usar la FPGA de la Parallella y la PYNQ y dejando de lado esto específico de md5, es una experiencia que me falta. La diferencia entre Parallella y PYNQ es el doble de FPGA.

 

Mainframe


Aunque tengo acceso parcial a un mainframe, se trata de un elemento crítico y debería programarlo en assembly por motivos de licencias. No sería la primera vez, en una materia de la facultad lo hice con un simulador, tendría que instalarme un hercules para hacer que funcione primero.

Tambien podría programarlo en cobol, pero estuve mirando y es una patada en los piés. No tengo acceso a la licencia para compilar en C, que sería lo más sencillo. Entiendo que hay oferta de acceso gratuito a mainframes para hacer pruebas, pero ya he perdido el impulso, quedará para otra reencarnación, si es que recuerdo la clave de acceso a este blog.


Se consigue acceso gratuito vía Master the Mainframe, pero parece que no tiene compilador C, habría que mirar. No vale la pena usar el emulador Hercules para la medición, pues queda desvirtualizada. Chiste nerd.

 

NEON


Otra prueba que no hice fue SIMD en ARM, que se llama NEON. Si buscás en ese lugar, al momento de escribir esto te lleva a una página que te ofrece:

 

Arm Architecture Reference Manual Armv8, for Armv8-A architecture profile

Contains reference documentation for all Advanced SIMD instructions.

 

pero al intentar ir por ahí, falla, no importa, con esas palabras claves se consigue un pdf con una versión beta del 2013 que tiene más de 5000 páginas. Tras mirar superficialmente, desistí y vía la descripción de instrinsics parece que soporta 4 x 32 bits, la mitad que AVX2, no logré encontrar rapido las instrucciones, justamente no tengo tiempo para esto. Hubiese servido para Raspberry Pi y celulares.


Cell Processor


Mencioné en la parte de GPGPU la existencia del Cell Processor, la verdad es que me quedé con la ganas. Algo que no dije, es que no es como una GPU, un conjunto de procesadores especializados que se agregan a un sistema, si no más bien como la Parallella o como los micros A de AMD, o sea un(os) cores llamados PPU (PowerPC Processing Element) tipo los ARM de zynq o los x86_64 de AMD más los SPE (Synergistic Processor Elements), como el multicore Epiphany de la Parallella o la GPU de AMD.

 

El problema era conseguir uno:

  • Playstation 3: hay un rango muy específico de modelos que permiten ejecutar linux y nadie lo tenía.
  • Servidor: había encontrado un server, lo vendían por ebay en Inglaterra
  • Placa PCI: tambien existe como una placa aceleradora.

 

Cell Processor
Cell Processor

Por suerte no tomé este camino, recientemente me enteré que aunque son increiblemente potentes al punto que se podrían seguir usando, son increiblemente difíciles de programar.

 

Sistemas Distribuido


No quiero dictar cátedra de sistemas distribuidos, más por que no la cursé, pero en mi mediano entender alcanzo a vislumbrar algunos escenarios.

 

Homogéneos

 

Hay múltiples técnicas para esto, mí única experiencia, académica, ha sido con MPI.

 

Agente en Javascript para el browser


No sé como andará la performance de webassembly, no apareció nada que no fuera youtube en google al buscar o que fuera una clara comparación fácil de leer e interpretar. Además está el problemita del multicore, no sé pero apuesto a que no se puede usar más de un core a la vez.

Todo eso no importa, por que bien aplica la frase "no somos machos pero somos muchos" y el agente en javascript para el browser se llama...

 

Botnet 

 

Del mismo modo que hay sitios que cuando entrás te dan un javascript para ponerte a minar bitcoin, se puede confeccionar un agente similar en Javascript o webassembly, si te conseguís muchos, todo bien.

 

Heterogéneo


Esto corresponde a un escenario más colaborativo y artesanal que el anterior,  donde podríamos distribuir la carga sobre CPUs con y sin SIMD, GPUs y FPGAs en una red no necesariamente local. Por ejemplo:


  • Mi laptop soporta AVX2 y GPU
  • La Parallella soporta FPGA, los 16 cores del Epiphany y los dos del PS, que no sé si soportan SIMD
  • Nexys4 soporta FPGA

 Como podrás apreciar, nos movemos en varias dimensiones

 

¿Cómo distribuir la carga?
¿Cómo distribuir la carga?

Estas deben estar coordinadas entre sí, fijate que para la nexys4 deberías contar con una computadora que le configure los rangos y esté atenta a los hallazgos, todo un subproyecto de por sí.

 

Y ahí empiezan las preguntas, ahora no estoy hablando de armar un sistema de cero, ahi sin duda hay diseñar para usar GPU y/o FPGA, digo a partir de lo uno (yo en este caso) tiene.

 

Si la FPGA y/o GPU es XXX veces más rápida, ¿vale la pena molestarse en usar las CPUs asociadas de ese dispositvio?

Otra, ¿y si ya tenemos las CPUs como puede ser un montón de netbooks o celulares? ¿alcanzará SIMD para justificar?


Luego hay que pensar en la distribución de carga entre todos los nodos, evidentemente hay que hacer lotes de distinto tamaño según la potencia del nodo. 

También hay que implementar un mecanismo de corte generalizado ante el primer hallazgo. Pero si en lugar de estar buscando estuviésemos calculando para almacenar, ¿Cómo hacemos para sacar toda esa información, sobre todo en FPGA?

Nexys4 DDR FPGA: Implementación de MD5

$
0
0
¿Venís de leer la intro, la parte 1, la parte 2, la parte 3,  la parte 4 y la parte 5?

 Contexto


Tenía unos pocos días para implementar en el Zynq de la Parallella el forzador brutal de MD5 para proponerlo a un evento.

Como veía que se me venía difícil, intenté prepararme un [entorno de TDD] que no usé, pero me puso en sintonía.

(Nota: cada texto entre llaves indica un link que aún no está disponible, en algún momento actualizaré)

Sabía algo de VHDL, pero mi punto de entrada a esa plataforma es Verilog así que intenté aprender un poco [migrando ejemplos] e investigando y eso me dejó con soltura en el lenguaje y el entorno de desarrollo.

En lugar de respetar el plan que me había propuesto, fui más tipo blitzkrieg, tomé algunos componentes de la migración y los hice funcionar juntos, en una primera etapa un contador con botones de start, stop y reset, display de 7 segmentos y unos leds de estado, lo cual ocupa casi nada de la PL disponible:



Sin el pipeline




Luego agregué el pipeline:



Diagrama de bloques simplificado



Y lo fui implementando stage por stage, primero a mano y luego me cansé y programé un [generador en C]. Tambien hice una salida de referencia con los valores intermedios y conectando sucesivamente la entrada del selector de display a estos estados intermedios en el pipeline, verifiqué que funcionara ok.



8 stages



Y así hasta el stage63... puse lógica de detección de coincidencia y perdí un tiempo ridículo en conseguir que start/stop, reset, found, done y running hicieran lo que yo quería.


El pipeline completo

Resultados


Tengo un circuito que calcula 4 GHashes en 40 segundos, esto es 100 MHashes por segundo, que es exactamente lo que había previsto.



Los IO no importan pues no harían falta en cada instancia, no?



Para la demo y para github lo instancié ocho veces, se acerca a 1100 MHashes que había alcanzado con GPGPU. Tambien para probar la superficie instancié 10 pero sin la lógica necesaria para distribuir los rangos de exploración, las potencias de 2 son más fáciles.


Deuda técnica y aprendizajes


Como que esto fué tiro con arco zen, pero sin la sabiduría que implica, casi que manotazos de ahogado, entiendo que si funciona es por una acumulación inconsciente de conocimiento, hay partes que no puedo explicar responsablemente.

El tiempo de síntesis e implementación arrancó en cuatro minutos y se duplicó con el pipeline completo, yo aproveché para ir haciendo estas entradas en el blog o ir pensando el siguiente paso (sin salvar, que puede afectar el flujo actual o siguiente), no es bueno irse a colgar ropa o ponerse a pensar en otra cosa.


Cerca de cuarenta horas a lo largo de cuatro días me llevó esto.

Cuando aprenda a [simular] supongo que será todo más fluido.

Hay que mirar permanentemente los warnings, sobre todo los critical warnings, varias veces me avisaron de cables no conectados.

Sin embargo, en la etapa de debugging del pipeline ocurrió algo muy interesante: por desviar hacia el display etapas intermedias y no usar la salida de pipeline para nada, lo quita por optimización:


Efecto de conectar el display al stage00 en lugar del stage63






Seguí con la parte 6


Recuperación de archivos en disco de Apple

$
0
0

Una persona conocida tuvo un problemita con un disco con una Apple, ni sabe bien, aparentemente perdió todos los archivos en un reemplazo de discos, no encuentra los discos viejos, conserva un disco de backup al cual borró.

En esta entrada doy una visión quizás menos técnica, es el complemento del contexto teórico que le faltó al rescate de la memoria de una cámara, donde sí están los detalles técnicos.


Existe una baja probabilidad de recuperar algo, veamos qué se puede hacer.

Lo primero es usar una instancia de linux en modo rescate/forense. Esto es, que el sistema no haga ningún tipo de modificación sobre ningún disco sin que se lo pidamos explícitamente. Para este escenario de rescate no es tan necesario pero sí para uno forense, donde hay que conservar intactas las evidencias. Por pura disciplina obremos como si fuera forense.

En el modo forense enfrentamos un adversario, alguien que ha intentado ocultar o eliminar información, en el modo rescate, el adverario es la torpeza del usuario o la mera mala suerte.

Lo ideal sería tener un bloqueador de escritura de hardware como lo que tengo en el trabajo, pero con la cuarentena no tengo acceso. Para windows existe un driver de encase que hace que todo lo que montes esté read-only, pero eso es por la tara de usar windows, en linux alcanza con montar read-only. Es verdad que podés fallar, pero tambien se te puede escapar un sudo rm -rf /


¿a quién no le ha pasado?
¿a quién no le ha pasado?

 

Dado que no tengo ganas de ajustar una instalación normal a "modo forense", voy a usar una máquina cualquiera arrancando con Kali Linux en modo forense, pero sin confiar, le voy a dar otro disco antes y ver que no le haga automount y cuando haga el mount sea read-only.

Kali Linux es una distribución orientada a la seguridad, se puede instalar o usar en modo live, que es lo que haré. No puedo anticipar mucho más pues no sé que voy a encontrar, no sé que particiones usa Apple, no sé nada.

 

Manos a la obra

 

Habiendo iniciado Kali, le conecto un disco cualquiera y verifico que no se haya montado y compruebo montarlo en modo read-only.

 

Es un poco desconcertante que te muestre en el desktop un ícono con las partición disponible para montar. No sé que no entendí de forense, evidentemente es para alguien con mas calle, pues cuando le hice doble click lo montón read-write. Ni me ofreció con el botón derecho el modo de montar.

No importa, es verdad que quien necesita hacer algo forense probablemente dedica buena parte de su tiempo a eso y no se le escapan estos detalles, nosotros los esporádicos, bien atentos.

Conecté entonces el disco a recuperar y uno de capacidad igual o superior. Monté el disco de rescate y tal como mostré en el rescate de la memoria de una cámara, usé photorec, le indiqué origen y destino y a esperar... cuatro horas dijo al comenzar, le llevó....

Seguramente ayudaría que los discos estuvieran conectados en distintas interfaces, pero es lo que tenía, no quiero saber lo que hubiera tardado de tratarse de USB 2.

Asumí que el uso de ambos discos sería similar y por eso puse el pendrive de inicio en USB2 y los discos juntos en USB3. Cuando llevaba 13 horas, para diagnosticar preferí usar ssh en lugar de interactuar directamente con la máquina, pues al ser una notebook, es incómoda por el teclado, el mousepad, la pantalla de muy alta resolución pero poco tamaño y por estar tirada en el piso.

Sólo tuve que ejecutar

sudo service ssh start

para poder entrar remoto.

Antes de investigar, ya que estoy me gustaría ver como marcha photorec, pero no tengo ganas de ir a mirar y desbloquear la sesión:

sudo apt install scrot

export DISPLAY=:0

scrot desktop.png

Ese scrot me captura la pantalla, lo transfiero por sftp y... nada, tiene que estar desbloqueada la sesión, no vale la pena, es menos esfuerzo ir hasta ahí, a menos que...

sudo loginctl unlock-sessions

no funcionó, hay que desactivar el screen-lock, demasiado esfuerzo, lo más correcto es abrir photorec dentro del programa screen para poder des/conectarse desde cualquier sesión, otra vez será.

Ahora falta evitar el sftp.

Para ello, en lugar de conectar con ssh conectamos con ssh -X, que permite abrir allá una aplicación y que su visualización sea aca.

xdg-open desktop.png

Casi, la abre pero no acá, si no allá, por el DISPLAY=:0, hay que decirle a scrot de otra manera.

Además en lugar de abrir con un visor usa un navegador, le lleva mil años, fijate como esta el load average:

 

La carga del sistema
La carga del sistema


Todo el manoseó es entonces:

ssh -X kali@192.168.1.xxx

scrot --display :0 desktop.png

ristretto desktop.png

Ojo que si ya existe desktop.png, sin avisarte salva como desktop_000.png

La mejor manera para la próxima vez:

  • Montar los discos desde la máquina
  • Correr photorec dentro de screen 
  • Hacer detach
  • Conectar con ssh -X
  • Abrir screen y hacer attach

Y cuidado con que no se active nada de Power Saving,  tras estar sin actividad, pues me mató la máquina. Por costumbre al reiniciar eliminé lo que ya había rescatado, probablemente fue un error, pues al arrancar nuevamente photorec, halló un archivo  que evidentemente es el journal y me ofreció continuar la sesión anterior, como que está preparado para sufrir interrupciones, mala suerte, ahí se perdieron dos horas más.

 

Volviendo al análisis del tráfico de los discos, hallé una buena fuente, vamos a probar algunos comandos.

dstat

sudo apt install dstat

Esta herramienta mide de todo, pero hoy sólo nos interesan los discos.

dstat -d 5

 

dstat
dstat

 

No hallé como decirle que use siempre MB para que no cambie la escala.

 

iostat

 

iostat
iostat

Parece indicar lo mismo: Aunque hay más bytes leidos que escritos, no hay una proporción tal que indique que una escritura más lenta podría ser mejor.

Una prueba que quise hacer fue saturar la lectura y la escritura para comparar con la obtenida. Para ello suspendí photorec y mirá lo que pasó con 10 segundos de intervalo:


suspendido
suspendido

 

Estuvo casi un minuto terminando de escribir, eso más bien indica que el cuello de botella es la escritura.

La lectura:

if=/dev/sdc of=/dev/null


saturación lectura
saturación lectura

La escritura:

if=/dev/zero of=borrar.bin

 

saturación escritura
saturación escritura


Para poder seguir de modo responsable el experimento, debería repetir las mediciones para USB2, pero no vale la pena, USB3 es 10 veces más rápido.

 

Recuperación

 

El disco este se usaba como backup, confiando en que el original estaba ok, se borró y se comenzó a usar nuevamente como backup. Luego se cayó en cuenta que el original no estaba ok, desesperación.

Para empeorar la cosa, pasaron varios meses entre las operaciones y la detección del inconveniente.

Lo que espero encontrar son un montón de carpetas borradas de la forma "Backup AAAA-MM-DD" con sus contenidos. Esto implica una alta repetición de archivos.

Para detectarlos voy a usar una técnica como la utilizada cuando lidié con archivos duplicados que es hashear todos los archivos y eliminar los duplicados


Lo que encontré:

5000 carpetas con nombre "recup_dir.NNNN" y con la fecha actual, en una estructura plana, esto es, no hay carpetas anidadas.

2000000 de archivos con nombres de una letra (f, r, t), un número de cerca de diez cifras, de los cuales el 10% tiene un nombre tras "_"

Cuando la letra es:

f: archivo, cuando además tiene un nombre, la fecha correcta, si no la actual.

t: thumbnail hallado dentro de algún archivo, fecha actual.


Al aplicar la técnica de agrupar por md5, se redujo a "sólamente" medio millón de archivos. Al quitar los thumbnails, 30 mil menos.

Abrí algunos archivos al azar y parecen estar ok. 

Los nombres de los archivos no parecen corresponder al nombre original si no a algo tomado de la metadata.


Le dejé a la persona dueña de los datos el trabajito de buscar lo que le interese.

















 


Selección de los archivos rescatados de un disco de Apple

$
0
0

Resumen, una persona borró un disco con un montón de backups de la forma:

Backup-AAA-MM-DD

Antes le corrí photorec y recuperé más de dos millones de archivos, iba a borrar algunos y con suerte reducir a medio millón, que igual es mucho, me he apiadado de la persona y le voy a meter más cerebro y trabajo.

 

Debido al conflicto entre hacer un proceso generico y lo particular de la información de la persona, lo que voy a dejar acá registrado no sirve como procedimiento, sirve para que te inspire. Además, no sabés cuántas veces tuve que reeescribir todo esto debido a los cambios producidos por cada nuevo descubrimiento.

En el caso en particular de la Apple, hay una cantidad considerable de archivos de importancia forense pero irrelevantes para mi objetivo.

Cuando estás explorando, como no sabés muy bien a dónde vás, el orden no importa mucho, pero hay que tener en cuenta algunas optimizaciones:

Si vamos a buscar archivos duplicados, hay que calcular md5 de cada archivo, entonces es mejor descartar antes de calcular por que el cálculo de md5 para muchos archivos consume mucho tiempo. 

 

Acciones

 

Hay algunas acciones que hay que repetir tras ejecutar otra, por ejemplo la lista de archivos hay que rehacerla tras renombrar las carpetas con la fecha tentativa.

 

Obtener lista de archivos

 

find . -type f > 00_archivos.txt

 

Obtener e identificar extensiones


cat 00_archivos.txt | rev | \
  cut -d "." -f 1 | rev | sort | \
  uniq -c | sort -nr > extensions_full.txt 

Puede haber basura, en mi caso todos los archivos que no tienen extensión, se pude filtrar o más fácil editar extensions_full.txt

Armé tres blacklists de extensiones:

[system]

plist$
DS_Store$

[photorec]

[0-9]\+.jpg$

[local]

.*txt$
.java$
.h$
.c$
etc...


Podría hacer blacklists más precisas, pero no vale la pena, mil archivos más o menos cuando estás con medio millón no lo amerita, al menos al comienzo. 

 

Descartar extensiones

 

Para el análisis trabajamos sobre 00_archivos con las blacklists:


wc -l 00_archivos.txt
2327955

grep -v -f local_extension_blacklist.txt \
   -f photorec_extension_blacklist.txt \
   -f system_extension_blacklist.txt 00_archivos.txt  | wc -l

890914

 

Archivos y extensiones eliminables


plist

Sirven para guardar información de apliciones, son 400 mil, chau.

 

.DS_Store


Contiene metadata de las carpeta como iconitos y posiciones, 30 mil, chau

 

txt

 

La persona no usa archivo de texto plano y además hay un número desproporcionado, 700 mil. Miré unos veinte al azar y parecen fragmentos xml, chau.

Si la persona hubiera usado archivos txt, debería haber creado alguna regla, ya sea con grep o con yara [1][2] para selecionar.

 

t*.jpg 


Los archivos con nombre t* son thumbnails que photorec extrajo de otros archivos, lo cual está ok para el propósito original de la herramienta, otros 40 mil menos


Analizar la cantidad


Este fué el análisis que me hizo comprender que en realidad no habían carpetas originales, sólo agrupamientos de 500 archivos.


for DIR in *; do
  echo -n "$DIR : "
  ls -1 "$DIR" \
  | grep -v -f photorec_extension_blacklist.txt \
  |  wc -l
done

 

Detectar y eliminar repeticiones

 

Obtener los hashes de los archivos cuyas extensiones no están en las blacklists.

grep -v -f local_extension_blacklist.txt \
   -f photorec_extension_blacklist.txt \
   -f system_extension_blacklist.txt 00_archivos.txt \
  > 01_archivos.txt

cat 01_archivos.txt | while read FILE; do
   md5sum "$FILE";
done > 01_hashes.txt

900 mil hashes, cinco horas...

 

Lo que te queda es:

hash..hash  ./recup_dir.xxx/fxxxxxxx.ext

Esto lo ordena:

sort 01_hashes.txt > 01_hashes.sort.txt

Esto extrae los hashes, elimina y cuenta los repetidos y ordena las frecuencias obtenidas:

cut -b -33 01_hashes.sort.txt | uniq -c | sort -nr \
> 02_only.unique.hashes.txt

Si contamos la líneas, sabemos cuantos archivos quedarán al final:

wc -l 02_only.unique.hashes.txt
243172

Ya casi estamos, salvo que no sé si me alcanza el lugar, veamos cuál es la situación:

  • El disco a rescatar tiene casi 900 GB libres
  • El disco de rescate tiene 120 GB libres
  • El rescate mide 730 GB.

 

Escenarios


Hay varios caminos a tomar:

 

Proyección ingenua

 

Tenía más de dos millones de archivos, queda un décimo de archivos, el rescate en bruto mide 730 GB, con unos 80 GB me arreglo para el rescate neto.

Mi instinto me dice que los archivos más grandes no estan tan repetidos.

 

El camino sin retorno

 

Hago el rescate neto sobre el disco a rescatar.

Lo bueno es que ya queda el disco tal como lo voy a devolver.

Lo malo es que si quisiera repetir el proceso no puedo pues ya pisé una parte.

 

El camino del cobarde con plata

 

Como tengo otro disco más, me puedo dar el lujo de copiar a otro lado.

 

La apuesta ingeniosa

 

Si en lugar de copiar, elimino los repetidos, no hay problema de espacio. Pero si me equivoco o quisiera recuperar algo perdido, tendría que repetir el proceso desde cero.

 

La solución ingeniosa


Si en lugar de borrar o copiar, simplemente muevo las cosas, no hay problemas de espacio, no toco el disco a rescatar, no pierdo los duplicados, que de todos modos no los necesito.


Lo cual me lleva inexorablemente a la respuesta correcta: borrar los repetidos.

La pregunta ahora es por qué hice todos estos rodeos. Muy sencillo. Por un lado no está mal pensar un poco más allá de lo evidente. Y fundamentalmente, por que me quedé enviciado con la idea de que los repetidos me iban a servir para identificar las carpetas, cosa ya descartada, así que a borrar.

¿Cuál sería la regla para borrar?

  • Leer cada linea de 01_hashes_sort, que es (hash,ruta)
    • Si es la primera de una serie de repeticiones, saltear
    • Si no es la primera de una serie, buscar y eliminar la ruta.

Más cerca de la implementación:

  • Leer la primera línea
  • Tomar nota del hash
  • Leer cada línea
    • Si el nuevo hash coincide, eliminar ruta 
    • Si no, tomar nota del nuevo hash

Más cerca de la implemetanción en awk:

  • Decidir que el hash tiene un valor arbitrario imposible
  • Leer cada línea
    • Si el nuevo hash coincide, eliminar ruta
    • Si no, tomar nota del nuevo hash

En awk:

BEGIN { hash="" }

/.*/ {
  if ( $1 == hash ) {
    print "rm " $2 " # " $1;
  } else {
    hash = $1;
    print "# keep " $2 "" $1;
  }
}


Cuando tengo miedo de embarrarla, acostumbro genera la impresión de los comandos en lugar de la ejecución concreta.


awk -f run.awk < 01_hashes.sort.txt > job.sh

Y compruebo que parezca correcto:

grep "# keep " job.sh | wc -l
243172

Y coincide, vamos para adelante.

sh job.sh

No termina nunca, es increiblemente ineficiente, si lo tuviera que hacer otra vez, vería la manera de que cada rm reciba varios archivos a la vez. 


Si estás en el medio del borrado y te asalta la impaciencia, esto te dice el porcentaje de lo realizado, te dejo de ejercicio entenderlo:


echo $(( $(grep -n  -m 1 $(ps ax | grep "rm " | grep -ve grep | grep -o "rm .*" | cut -b 4-) job.sh | cut -d":" -f 1) * 100 / $( grep "rm " job.sh | wc -l  )   ))

 

Si soy muy sagaz quizás ya te diste cuenta del error que cometí, lo noté mientras esperaba que termine el borrado, el primer borrado... ¿ya te diste cuenta?

El análisis de los repetidos fue sobre los archivos que no están en las blacklists de extensiones. Falta borrar esos tambien. Esta vez cada rm recibe 100 archivos

echo -n "rm "
count=0;
grep -f local_extension_blacklist.txt \
     -f photorec_extension_blacklist.txt \
     -f system_extension_blacklist.txt \
     00_archivos.txt \
| while read FILE;  do
   count=$(( $count + 1 ))
   echo -n " $FILE "
   if [ $count -eq 100 ] ; then
     echo
     echo -n "rm "
     count=0;
   fi;
done > job2.sh


wc -l job2.sh
14370

Ese número por 100 más 647764 de los borrados duplicados da 2084764 y más 243172 nos queda 2327936, que se parece bastante al número total de archivos recuperados, 2327955, tiene 19 de diferencia que debe ser el número de archivos de la última línea de job2.sh


 

El final


Y el empujoncito final, agrupar.

Para que la persona pueda hacer algo con todo esto que quedó, generé esta estructura:

  • rescatado
    • imagenes
      • jpg
      • png
      • otras
    • documentos
      • pdf
      • doc
      • docx
      • otros 
    • otros

 

y asi..

El problema es que de algunos tipos de archivos hay hasta más de 10 mil ejemplares y no es buena idea trabajar con carpetas tan grandes, de hecho photorec las hace de 500. Hay que hacer un script tal que tome cada archivo y lo ponga en una carpeta según la jerarquía anterior y además los amontone en carpetas según un límite.


Lo primero es recuperar nuestra frecuencia de extensiones, igual que antes pero con distintos nombre:


find . -type f > 10_archivos.txt

cat 10_archivos.txt | rev | \
  cut -d "." -f 1 | rev | sort | \
  uniq -c | sort -nr > extensions_full.txt

Estos son algunos de mis números:

 

  52000 png
  21000 jpg
  19000 html
  12000 gz
  11000 xml
   8500 pdf
   3000 docx
   1700 gif
   1500 sqlite
   1200 zip
    700 mov
    200 wav
    100 mp3
 

Pensaba particionar pero me cansé, hice un listado para cada tipo (audio, video, comprimidos), con nombre "mover.txt" y luego generé un archivo de patrones:


cat mover.txt| while read EXT; do
   echo ".*\.$EXT$";
done > mover.pattern 

Esto da algo así como:

.*\.mov$
.*\.avi$
.*\.mp4$
.*\.mpg$
.*\.swf$
.*\.webm$

Luego ejecuté:

grep -f mover.pattern 10_archivos.txt | while read FILE; do
  mv "$FILE" rescate/video;
done

Y así para cada grupo.

Elegí algunas extensiones eliminarlas, por ejemplo sqlite. Usé algo parecido a lo anterior, pero

grep -f borrar.pattern 10_archivos.txt | xargs rm

 

Si se le hace inusable a la persona, me dá el disco de regreso y haré el particionamiento.

Para copiar al disco original que tiene hfs plus como filesystem, tuve que pasarme a otra máquina basada en ubuntu para poder instalar hfsprogs, kali no lo tiene a la vista.
 
sudo mount -t hfsplus -o remount,force,rw /media/xxx

Luego, el disco está con root como owner y  hay un usuario 99.99, así que tuve que copiar como root y luego:
 
chown -R 99.99

 

Lo que no fué

 

Esto lo menciono pues me gusta el razonamiento, pero al hacer el análisis de cantidades de archivos por carpeta con lo que pensaba que me ayudaría a descubrir cuáles eran de datos y cuáles del sistema, me encontré con que las carpetas de rescate sólo cumplen la función de no hacer una sola carpeta con millones de archivos, no hay rastro de las estructura, son sólo archivos sueltos.

 

Esperaba que hubieran carpetas que representaran a la misma carpeta pero siendo la misma a travéz del tiempo. De ser así:

  • Hay carpetas del sistema que no nos interesan.
  • Hay carpetas de datos que no nos interesan.

Si en esta instancia eliminara los repetidos, tendría esta situación:

  • carpeta 01 (yo no lo sé pero es la última versión)
    • archivo 01
    • archivo 02
    • archivo 03
  • carpeta 02 
    • archivo 01
    • archivo 02
    • archivo 03

Me resulta más útil poder asignar una fecha a cada carpeta utilizando la fecha más vieja que encuentre adentro pero menor a la fecha de rescate y luego usar las repeticiones para poder relacionar cuales carpetas son la misma.

 

for DIR in  recup_dir.*; do
  date=$( ls "$DIR" --full-time -l \
         | grep -ve 2021-01-01 \
         | head -2 | tail -1 \
         | sed 's/ \+/ /g' | cut -d"" -f 6 )
  if [ $date ] ; then
    echo mv "$DIR""$DIR.$date"
    mv "$DIR""$DIR.$date"
  else
    echo "NO DATE FOR $DIR"
  fi
done


Este es el script para revertir:

ls -d recup_dir* | grep "-" | while read DIR;  do
  DST=$(  echo "$DIR" | cut -d "." -f -2 )
  mv $DIR $DST
done


[1] https://seguridad-agile.blogspot.com/2019/11/identificando-versiones-de-programas.html

[2] https://seguridad-agile.blogspot.com/2019/03/jugando-con-los-rayos-1-obteniendo-el.html

 


Consejos para compartir información

$
0
0

Esta entrada es el resultado de emprolijar y extender lo conversado en Servidor MQTT en casa (en red privada)

 

Contexto


MQTT es un protocolo para el intercambio de mensaje en modo publisher/subscriber, esto es, que cada nodo se subscribe a un nombre de "topic" y publica o lee ahí, muy utilizado en IoT.

En una situación normal basta con que un nodo que tiene una dirección IP pública escuche en el puerto apropiado (1883 u 8883) pero a veces los proveedores de internet no dejan pasar el tráfico y además hay que lidiar con NATeos (cuando tras una IP se esconden muchas máquinas).

En la conversación se habla de cómo configurar el router de Fibertel y algunas ideas para diagnosticar y configurar la conexión.
 

En algún momento, uno se siente tentado de decir qué router tiene e incluso la IP, lo cual puede no ser buena idea y también mostrar capturas de pantallas con información de la red.
 

Esta información puede ser aprovechada por algún atacante, veamos los detalles:

 

IP

 

La IP es el punto de entrada para el atacante, el resto es información complementaria.
 
Aún sin tener la IP, el atacante puede mandar un mail a la persona o a todo el grupo con algo interesante que contenga un link a un sistema que tome nota de la IP de origen, que probablemente sea la de interés para el atacante. Bien puede ser en el caso de MQTT, "tengo este servidor si querés probar" o "fijate esta documentación".

 

Puertos abiertos  

 

En esta imagen se pueden ver los puertos abiertos y unas etiquetas que me sugieren la función de los equipos:

 

Port Forwarding
Port Forwarding

 

Direcciones MAC

 

MAC Addresses
MAC Addresses


 
En la otra, las direcciones MAC. ¿qué importa si son internas? Pues ocurre que la mitad izquierda es el identificador de la marca de la placa y hay bases de datos que incluso llegan a determinar qué equipo, por ejemplo si es una RPI, un router, un celular, la marca, si es placa wifi o ethernet, depende... y cuando no está en la base de datos podés suponer que es un VM.
 
Veamos... mmh, aburrido, pero algo es:
 
68:b5:99    Hewlett Packard
40:30:04    Apple
58:55:ca    Apple
00:23:6c    Apple
4c:0f:6e    Apple

 
Estoy seguro que había manera de obtener más información, pero no recuerdo dónde, lo anterior lo saqué de los dos primeros buscadores online, luego, escarbando un poco más y haciendo el proceso inverso a modo de ejemplo sin relación con las direcciones obtenidas:
 

 
00-10-5A-73-7F-81 corresponde a "Fast Etherlink XL in a Gateway 2000".
 
002000f0f85e es "Lexmark (Print Server)".
 
Las direcciones 02:42:xx:xx:xx:xx son de Docker.

 
Esto se combina con la información anterior para los puertos expuestos a internet.

 

Modelo Router

 

Podés decirlo explícitamente en un mensaje o como en la primera imagen estar en la misma captura. 

 
Fijate que alguien que se dedica quizás pueda determinar marcas e incluso modelos de dispositivos por otra información de la imagen, aunque hayas borrado de ésta lo evidente, por ejemplo por el diseño o por mensajes tipo "soporta 32 entradas".

 

Combinación

 

Combinando toda esta información, el atacante esta en mejores condiciones sin haberte tocado. Esto es que te gastaste un montón de plata en tu IDS (Intrusion Detection System: sistema que podría detectar una exploración de red equivalente y alertarte) y no te detectó nada. Si el atacante quiere explorarte desde afuera o ya logró meter apenas el piecito, su exploración va a ser mucho más específica y discreta, reduciendo las probabilidades de que le detectes.


Pero la pregunta es, ¿por qué y cómo podría alguien atacarme?

 

Cómo

 

Conociendo la IP y los dispositivos disponibles, puede haber que alguno tenga vulnerabilidades conocidas y quien ataca sólo tiene que buscar en internet un script que sirva.

 

Por qué

 

Yo lo haría para divertirme o practicar, al menos la parte de exploración, si no fuera por que a la gente no le gusta que le hagan estas cosas, igual podría hacerlo desde un nodo gratuito de aws/azure/googleXXX. Además se parece demasiado a trabajar y eso le quita la diversión

Otras personas podrían estar buscando armar una botnet o tener una curiosidad menos restringida que la mía.

O quizás trabajás en un lugar importante y sos sólo un medio para llegar hasta ahí. Considerá que últimamente (desde el covid) ha aumentado de modo infernal el trabajo desde el hogar, haciendo que hayamos pasado de un grupo con un cierto conocimiento técnico a una inmensa masa heterogénea de usuarios, todos conectados por VPNs a sus trabajos. Como atacante no me interesás, me interesa tu VPN y tengo que pasar por tu casa. Es como si vivieras en una casa con sótano al lado de un banco.

En la lista donde se originó esta conversación hay 5000 personas, con un 0.1% de malicia ya tenés 5 personas interesadas. Además, esta lista es pública, puede estar siendo monitorizada por una cantidad indefinida de personas.

En realidad, el mayor riesgo que corrés en el día a día con tu router conectado a internet (no hay más remedio, no? para qué querrías el router si no?) no viene por acá sino de los ataques automátizados, para los cuales tenés que hacer hardening, a continuación.
 
Tambien está la cuestión de disciplina e imagen, puede ocurrir que un potencial cliente o empleador exigente considere en sus decisiones tus acciones online.

 

Cómo lidiar con el error

 

  • Vía web eliminar el mensaje, luego reenviarlo correctamente. Igual hay a quienes les ha llegado por mail o ya lo han visto en la lista desde la página.
  • Cambiar los puertos.
  • Refrescar la IP si era dinámica.
  • Hardening de los equipos (esto hay que hacerlo de todos modos...)
    • Cambiar credenciales por defecto
    • Poner credenciales fuertes y/o usar certificados
    • Actualizar firmware
    • Poner un WAF o firewall configurado para lo que estés protegiendo
    • etc..
Cuando ves que fue otra persona la que publicó su información, consultale antes de avisar públicamente para darle oportunidad de protegerse. Aunque yo pido permiso, "la ley de la selva de la ciberseguridad" contempla que cuando otro mete la pata se le avisa pero si no responde, pasado un tiempo se hace público el asunto para el beneficio común. Y hay quienes por torpeza o porque no están de acuerdo con la Responsible Disclosure, te pueden prender fuego.

 

¿Cómo hago para compartir información en la lista de modo útil y menos inseguro?


Ok, ya tengo para este tipo de información un cierto criterio para elegir si exponerla o no, pero, no me dedico a la seguridad de la información, ¿cómo hago para no volver a meter la pata? Es una interminable cadena de "si" y relaciones tenues entre el riesgo que estés dispuesto a aceptar, el costo de ofuscar la información y los beneficios de exponerse.

La manera es ponerse en el lugar del otro y pensar si la información que se expone nos hace únicos, no es sencilla de obtener por otros medios, podría formar parte de una cadena de dependencias y para acceder a un recurso protegido.

Todo esto basado en que hay que saber lo más posible de tecnología y prestar atención a corregir cuando metas la pata.






Lidiando con un scanner

$
0
0

Quiero usar un scanner Cannon Lide 300 que dice ser soportado por sane pero no es visto, prefiero no instalar nada o lo menos posible del fabricante.

No es tanto para evitar un troyanito, con mi conocimiento y el análisis que estoy haciendo, probablemente pasaría por debajo del radar, es sólo puro orgullo, hacer andar algo bajo mis reglas.

Voy a mostrar sin explicar mucho como se usa un poco de sane, lsusb, dpkg, file, ldd, apt, strace para comprender el proceso de instalación.

El objetivo, fallido, es no usar el programa de Cannon.


Lo primero que hice fue:

sane-find-scanner


could not open USB device 0x1d6b/0x0001 at 004:001: Access denied (insufficient permissions)
could not open USB device 0x046d/0xc534 at 003:002: Access denied (insufficient permissions)
could not open USB device 0x1d6b/0x0001 at 003:001: Access denied (insufficient permissions)
  # No USB scanners found. If you expected something different, make sure that...


Es razonable, veamos con sudo

sudo sane-find-scanner


found USB scanner (vendor=0x04a9 [Canon], product=0x1913 [LiDE 300]) at libusb:001:004
  # Your USB scanner was (probably) detected. It may or may not be supported by
  # SANE. Try scanimage -L and read the backend's manpage.



Hagámosle caso:

sudo scanimage -L

tras un ratito...

No scanners were identified.


Ya estoy seguro de dos cosas, quizás sane si, pero linux no sabe que hacer con el scanner o cómo hacerselo llegar, eso es udev.

Y además puede ser que haga falta un driver.

Sigamos dando vueltas por ahí, a ver que pasa en /dev

find /dev > antes.txt

conectar

find /dev > despues.txt

comparar

diff antes.txt  despues.txt

12a13
> /dev/vboxusb/001/004
120a122
> /dev/char/189:3
384a387
> /dev/bus/usb/001/004



Ok, vemos que probablemente virtualbox está disponibilizándolo para una virtual



lsusb
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 004: ID 04a9:1913 Canon, Inc.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub


un poco más de detalle:

lsusb -v -s 001:004

trae información y por stderr dice

Couldn't open device, some information will be missing

ya habíamos tropezado con esa piedra:

sudo lsusb -v -s 001:004


Entre otra cosas dice:

iManufacturer           1 Canon
iProduct                2 LiDE 300
iSerial                 3 46D4C3

Sólo faltaría conseguir los drivers y apuesto que tiene que haber unas reglas de udev

Tras bajar el instalador y descomprimir el instalador, con

dpkg -x scangearmp2-3.70-1-deb/packages/scangearmp2_3.70-1_amd64.deb  .

podemos ver el interior y confirmar las sospechas:

./usr
./usr/lib
./usr/lib/libcncpnet2.so.1.2.4
./usr/lib/bjlib
./usr/lib/bjlib/canon_mfp2_net.ini
./usr/lib/bjlib/canon_mfp2.conf
./usr/lib/libcncpnet30.so.1.0.0
./usr/lib/libcncpnet20.so.1.0.0
./usr/lib/libcncpmslld2.so.3.0.0
./usr/bin
./usr/bin/scangearmp2
./usr/share
./usr/share/scangearmp2
./usr/share/scangearmp2/scangearmp2.glade
./usr/share/doc
./usr/share/doc/scangearmp2
./usr/share/doc/scangearmp2/LICENSE-scangearmp-3.70SC.txt
./usr/share/doc/scangearmp2/LICENSE-scangearmp-3.70EN.txt
./usr/share/doc/scangearmp2/changelog.Debian.gz
./usr/share/doc/scangearmp2/LICENSE-scangearmp-3.70FR.txt
./usr/share/doc/scangearmp2/LICENSE-scangearmp-3.70JP.txt
./usr/share/doc/scangearmp2/copyright
./usr/share/locale
./usr/share/locale/zh
./usr/share/locale/zh/LC_MESSAGES
./usr/share/locale/zh/LC_MESSAGES/scangearmp2.mo
./usr/share/locale/ja
./usr/share/locale/ja/LC_MESSAGES
./usr/share/locale/ja/LC_MESSAGES/scangearmp2.mo
./usr/share/locale/fr
./usr/share/locale/fr/LC_MESSAGES
./usr/share/locale/fr/LC_MESSAGES/scangearmp2.mo
./usr/share/locale/de
./usr/share/locale/de/LC_MESSAGES
./usr/share/locale/de/LC_MESSAGES/scangearmp2.mo
./etc
./etc/udev
./etc/udev/rules.d
./etc/udev/rules.d/80-canon_mfp2.rules


Tenemos varias coas interesantes:

en /usr/share/doc archivos de documentacion


en /usr/share/locale las traducciones disponible


en /usr/share/scangearmp2 pueden haber problemas, ese .glade si mal no recuerdo es la configuración de la interfaz gráfica de la aplicación, esto podría generar instalación de dependencias, veamos...

file /usr/bin/scangearmp2

scangearmp2: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.15, BuildID[sha1]=028fbac2701f687da994b21fb506a92aedb587c3, stripped



ese dinamically linked amerita un ldd:

ldd scangearmp2
    linux-vdso.so.1 =>  (0x00007ffdb31b3000)
    libgtk-x11-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 (0x00007f3071b38000)
    libgdk-x11-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgdk-x11-2.0.so.0 (0x00007f3071883000)
    libatk-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libatk-1.0.so.0 (0x00007f307165e000)
    libgio-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0 (0x00007f30712d6000)
    libpangoft2-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 (0x00007f30710c0000)
    libgdk_pixbuf-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0 (0x00007f3070e9e000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3070b95000)
    libpangocairo-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 (0x00007f3070988000)
    libcairo.so.2 => /usr/lib/x86_64-linux-gnu/libcairo.so.2 (0x00007f3070674000)
    libpango-1.0.so.0 => /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0 (0x00007f3070428000)
    libfreetype.so.6 => /usr/lib/x86_64-linux-gnu/libfreetype.so.6 (0x00007f307017e000)
    libfontconfig.so.1 => /usr/lib/x86_64-linux-gnu/libfontconfig.so.1 (0x00007f306ff3b000)
    libgobject-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 (0x00007f306fce8000)
    libgthread-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgthread-2.0.so.0 (0x00007f306fae6000)
    libgmodule-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0 (0x00007f306f8e2000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f306f6da000)
    libglib-2.0.so.0 => /lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f306f3c9000)
    libusb-1.0.so.0 => /lib/x86_64-linux-gnu/libusb-1.0.so.0 (0x00007f306f1b1000)
    libcncpmslld2.so => not found
    libcncpnet2.so => not found
    libcncpnet20.so => not found
    libcncpnet30.so => not found

    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f306ef94000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f306ebca000)
    libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f306e890000)
    libXfixes.so.3 => /usr/lib/x86_64-linux-gnu/libXfixes.so.3 (0x00007f306e68a000)
    libXrender.so.1 => /usr/lib/x86_64-linux-gnu/libXrender.so.1 (0x00007f306e480000)
    libXinerama.so.1 => /usr/lib/x86_64-linux-gnu/libXinerama.so.1 (0x00007f306e27d000)
    libXi.so.6 => /usr/lib/x86_64-linux-gnu/libXi.so.6 (0x00007f306e06d000)
    libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2 (0x00007f306de62000)
    libXcursor.so.1 => /usr/lib/x86_64-linux-gnu/libXcursor.so.1 (0x00007f306dc58000)
    libXcomposite.so.1 => /usr/lib/x86_64-linux-gnu/libXcomposite.so.1 (0x00007f306da55000)
    libXdamage.so.1 => /usr/lib/x86_64-linux-gnu/libXdamage.so.1 (0x00007f306d852000)
    libXext.so.6 => /usr/lib/x86_64-linux-gnu/libXext.so.6 (0x00007f306d640000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f306d426000)
    libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f306d204000)
    libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f306cfe9000)
    libharfbuzz.so.0 => /usr/lib/x86_64-linux-gnu/libharfbuzz.so.0 (0x00007f306cd8b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f3072183000)
    libpixman-1.so.0 => /usr/lib/x86_64-linux-gnu/libpixman-1.so.0 (0x00007f306cae3000)
    libpng12.so.0 => /lib/x86_64-linux-gnu/libpng12.so.0 (0x00007f306c8be000)
    libxcb-shm.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-shm.so.0 (0x00007f306c6ba000)
    libxcb-render.so.0 => /usr/lib/x86_64-linux-gnu/libxcb-render.so.0 (0x00007f306c4b0000)
    libxcb.so.1 => /usr/lib/x86_64-linux-gnu/libxcb.so.1 (0x00007f306c28e000)
    libthai.so.0 => /usr/lib/x86_64-linux-gnu/libthai.so.0 (0x00007f306c085000)
    libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f306be5c000)
    libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f306bc54000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f306ba50000)
    libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f306b7e0000)
    libudev.so.1 => /lib/x86_64-linux-gnu/libudev.so.1 (0x00007f3072349000)
    libgraphite2.so.3 => /usr/lib/x86_64-linux-gnu/libgraphite2.so.3 (0x00007f306b5ba000)
    libXau.so.6 => /usr/lib/x86_64-linux-gnu/libXau.so.6 (0x00007f306b3b6000)
    libXdmcp.so.6 => /usr/lib/x86_64-linux-gnu/libXdmcp.so.6 (0x00007f306b1b0000)
    libdatrie.so.1 => /usr/lib/x86_64-linux-gnu/libdatrie.so.1 (0x00007f306afa8000)



estamos bien, sólo faltan:

        libcncpmslld2.so => not found
        libcncpnet2.so => not found
        libcncpnet20.so => not found
        libcncpnet30.so => not found



Preguntémosle al sistema instalador a ver que dice:

dpkg -I scangearmp2_3.70-1_amd64.deb

 
Package: scangearmp2
 Version: 3.70-1
 Architecture: amd64
 Maintainer: Canon Inc. <sup-debian@list.canon.co.jp>
 Installed-Size: 668
 Depends: libatk1.0-0 (>= 1.29.3), libc6 (>= 2.7), libcairo2 (>= 1.2.4), libfontconfig1 (>= 2.8.0), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libglib2.0-0 (>= 2.16.0), libgtk2.0-0 (>= 2.12.0), libpango1.0-0 (>= 1.14.0) | libpango-1.0-0, libstdc++6 (>= 4.1.1), libusb-1.0-0 (>= 2:1.0.6)
 Section: graphics
 Priority: optional
 Description: ScanGear MP for Linux.
  This ScanGear MP provides scanning functions for Canon Multifunction Inkjet Printer.


mmh, necesito saber que me va a pedir, si le pido instalar y no tiene dependencias sigue de largo sin preguntar, necesito algo tipo:

apt install --simulate scangearmp2-3.70-1-deb/packages/scangearmp2_3.70-1_amd64.deb

Reading package lists... Done
Building dependency tree       
Reading state information... Done
Note, selecting 'scangearmp2' instead of 'scangearmp2-3.70-1-deb/packages/scangearmp2_3.70-1_amd64.deb'
The following NEW packages will be installed:
  scangearmp2
0 upgraded, 1 newly installed, 0 to remove and 274 not upgraded.
Inst scangearmp2 (3.70-1 local-deb [amd64])
Conf scangearmp2 (3.70-1 local-deb [amd64])



Esto sugiere que los libcncp* quizás sean lo que provée el mismo instalador y si miramos lo que ya hicimos, se confirma:

./usr/lib/libcncpnet30.so.1.0.0
./usr/lib/libcncpnet20.so.1.0.0
./usr/lib/libcncpmslld2.so.3.0.0



que era una de las cosas interesantes, sólo nos queda una por ver, lo de udev, son como 70

ATTR{idVendor}=="04a9", ATTR{idProduct}=="1828", MODE="666"
ATTR{idVendor}=="04a9", ATTR{idProduct}=="183e", MODE="666"
ATTR{idVendor}=="04a9", ATTR{idProduct}=="1844", MODE="666"
ATTR{idVendor}=="04a9", ATTR{idProduct}=="1845", MODE="666"


y si no me equivoco lo único que hace es poner los permisos para no tener que ser sudo/root


Necesitaría ver si hay algún script en el .deb

dpkg -e  scangearmp2-3.70-1-deb/packages/scangearmp2_3.70-1_amd64.deb

genera una carpeta DEBIAN

conffiles  control  md5sums  postinst  postrm

en control está lo mismo que dijo con -I

en conffiles la ruta de udev

en postinst

#!/bin/sh

if [ -x /sbin/ldconfig ]; then
    /sbin/ldconfig
fi

#reload udev rules
if [ -x /sbin/udevadm ]; then
    /sbin/udevadm control --reload-rules 2> /dev/null
    /sbin/udevadm trigger --action=add --subsystem-match=usb 2> /dev/null
fi



Excelente, lo que le está diciendo al sistema es que tome los nuevos .so y avisarle a udev de las nuevas reglas


Ha llegado el momento de actuar, poner las reglas y avisar:

sudo chown root.root ./etc/udev/rules.d/80-canon_mfp2.rules
sudo cp  ./etc/udev/rules.d/80-canon_mfp2.rules /etc/udev/rules.d
sudo /sbin/udevadm control --reload-rules
sudo /sbin/udevadm trigger --action=add --subsystem-match=usb


Mirá mamá! sin sudo!

lsusb -v -s 001:004

Bus 001 Device 004: ID 04a9:1913 Canon, Inc.
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0        64
  idVendor           0x04a9 Canon, Inc.
  idProduct          0x1913
  bcdDevice            1.00
  iManufacturer           1 Canon
  iProduct                2 LiDE 300
  iSerial                 3 XXXXXX
  bNumConfigurations      1
  Configuration Descriptor:



Tenía la infundada esperanza de que de algún modo mágico sane ya lo viera con scanimage. Sería magia, pues con sudo ya debería haber funcionado, esto fueron sólo los permisos, quizás sea hora de leer la documentación de sane


Primero vamos a

http://www.sane-project.org/lists/sane-mfgs-cvs.html

control f, lide 300

que nos dice el backend que entiende este dispositivo:

http://www.sane-project.org/man/sane-pixma.5.html

¿Cómo hacerlo andar? Hace mucho tiempo hice andar un microteck II o III SP (SP significa Simple Pass, de cuando los scanner tenian que pasar tres veces, una vez por cada color) y me ahora me suena lo del backend, pero scanimage sólo entiende --device

scanimage --device /dev/bus/usb/001/004 -L


scanimage --device /dev/char/189:3 -L

Volviendo a la man page, dice como registrar los nombres, entiendo que

[/etc/sane.d/pixma.conf]
pixma:04A91913_46D4C3


pero nada, preguntémosle a strace a ver que archivos está leyenco scanimage

strace -eopen scanimage -L

open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/x86_64-linux-gnu/libsane.so.1", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("./dll.d", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
open("./dll.d/hplip", O_RDONLY)         = 4
open("./dll.conf", O_RDONLY)            = 3
open("./dll.aliases", O_RDONLY)         = -1 ENOENT (No such file or directory)
open("/etc/sane.d/dll.aliases", O_RDONLY) = -1 ENOENT (No such file or directory)



y despues un montón de /dev, precedidos de...


open("./sharp.conf", O_RDONLY)          = 27


está leyendo cada .conf de /etc/sane.d, incluyendo el amigo pixma.conf

y para cada backend:

open("/dev/bus/usb/001/004", O_RDWR)    = 96


Le pido ahora que sólo me cuente de la ruta de interés


strace  -P  /dev/bus/usb/001/004 scanimage  -L
open("/dev/bus/usb/001/004", O_RDWR)    = 9
ioctl(9, USBDEVFS_GET_CAPABILITIES, 0x558209e4f2c0) = 0
close(9)                                = 0
open("/dev/bus/usb/001/004", O_RDWR)    = 12
ioctl(12, USBDEVFS_GET_CAPABILITIES, 0x558209e4d330) = 0
close(12)                               = 0
open("/dev/bus/usb/001/004", O_RDWR)    = 15
ioctl(15, USBDEVFS_GET_CAPABILITIES, 0x558209e618f0) = 0
close(15)                               = 0



Para que no sea tanta info, comenté todos los backends en /etc/sane.d/dll.conf salvo pixma

Nada, ha llegado el momento de rendirme e instalar el software a ver si realmente anda...

dpkg -i scangearmp2-3.70-1-deb/packages/scangearmp2_3.70-1_amd64.deb

...como piña. Funciona excelente.

Si quisiera seguir, tendría que capturar el tráfico usb para ver qué está ocurriendo...

Puede ser que la máquina donde estoy instalando tenga una distro vieja. Uno de estos días, cuando haga la actualacion y tenga que reinstalar esto, veré si hay novedades.






Basic Digital Design EAMTA 2021

$
0
0

Gracias a la cuarentena tenía algunos días de vacaciones sin tomar, aproveché para tomar un sorpresivo curso, bastante extenso, cinco días de seis horas y tres de cinco, 45 horas en total, de diseño digital básico con Verilog, en el marco del evento EAMTA 2021, a cargo de Ariel Pola y Federico Zacchigna.

Pese a lo "básico" del curso, se vislumbran "situaciones extremas", donde se muestra el eterno conflico entre La Potencia, La Velocidad y El Área. No es algo a lo que alguien como yo pueda estar expuesto siquiera con baja frecuencia. Pero para mí que ya sabía algo de antes por haber cursado CLP, estudiado unos libros, hecho algunos moocs y practicado en mis experimentos, me resultó excelente. No sé para alguien que viene de cero FPGA o a alguien con conocimientos previos como yo pero que le moleste reforzar, cómo le habrá resultado.

Es como si estuvieras viendo en un curso introductorio de C como usar assembly, escenario que podría corresponder al de sistemas embebidos de muy bajos recursos.

A diferencia de los otras actividades similares que he transitado, esta implica un conocimiento mayor de técnicas digitales, pues estamos hablando de por ejemplo comprender que en el caso de implementar un multiplicador de una variable por una constante, se puede eliminar el hardware necesario para los ceros de la constante.

Los detalles finos de estos conceptos vistos superficialmente se ven exhaustivamente en otro curso o materia que se debe llamar algo así como "Digital Advanced Digital Design", que parece ser mucho más difícil, ya veremos si me quedan días de vacaciones y neuronas para cuando llegue.

Aprendí, recordé, reforcé y completé cosas que vengo viendo de algún modo desde hace más de 30 años.

El último día lo sobreviví comiendo exclusivamente chocolate blanco...

Si la medida objetiva de mi satisfacción con un curso está dada por mi grado de participación, en este caso ha sido tan grande que debo incluso haber molestado a los docentes y compañeros de cursada.

 

Trabajo Práctico


El trabajo práctico es una extensión de los laboratorios desarrollados como tarea durante la cursada, en el momento que escribo esto estoy considerando proponer mi propio trabajo práctico para optimizar mi esfuerzo, pero tengo cierta reticencia en parte para no generarles a los docentes trabajo extra, en parte por que es más difícil y por que el tema que resuelve no coincide con el tema protagonista del curso, que es procesamiento de señales. Ese mismo tema es que me induce a proponer mi propio TP, pues mi ingnorancia del mismo produce que no termine de entender lo que estoy haciendo aunque si cómo lo estoy haciendo.

 

Logística 


Algunos tips de cómo lidiar con algunas fallas.

 

Para el uso de classroom

 

  • Los archivos que tienen preview como txt y pdf, hay que pedirle abrir en otra ventana y ahí recién ofrece download.
  • Hubiese sido más cómodo que un zip con todos los archivos para bajar de un solo tiro

 

Vivado

 

Falla al inicio

Tras invocar vivado, este se cierra diciendo que:

Caused by: java.lang.IllegalArgumentException: Window must not be zero

Primero pensé que era por haber estado jugando al Dune2 desde unas semanas antes, no como una especie de castigo divino, es que estaba en un brote procrastinador nulo y en algún momento puse en full screen a dosbox me rompió el multihead y lo restauré.

Luego, encontré referencias a las versiones de java, independientes de la versión de Xilinx, relacionadas a multihead. Hay que desactivar las pantallas adicionales, arrancar vivado, reactivar las pantallas y listo. Igual muy raro porque no me había ocurrido antes con las otras versiones y ahora si me ocurre hasta donde probé.

ILA

 

Al incorporar el ILA (luego veremos que es eso) fallaba diciendo que ....

WARNING: [Vivado 12-818] No files matched '/home/projects/ej01_ila_vio_v2/ej01_ila_vio_v2.srcs/sources_1/ip/ila_0_1/ila_v6_2/constraints/ila_impl.xdc'
ERROR: [Common 17-55] 'set_property' expects at least one object.


El problema es que ese archivo si existe. Supuse un problema de concurrencia, pero con un solo core también falló.

No se arregló:

  •    haciendo source de settings64.sh
  •    iniciando del iconito
  •    usando un solo core
  •    primero VIO, luego ILA
  •    ILA solita


Viendo con más detalle, dice en la consola que ejecutó:

source ila_0.tcl -notrace

tuve que hacer cd hasta el proyecto y ejecutar:

source ./ej01_ila_vio_v3.runs/ila_0_synth_1/ila_0.tcl -notrace

identifiqué dos menciones a ila_impl.xdc, puse un

puts "antes del primer get files"


y obtuve:

source ./ej01_ila_vio_v3.runs/ila_0_synth_1/ila_0.tcl -notrace
INFO: [IP_Flow 19-234] Refreshing IP repositories
INFO: [IP_Flow 19-1704] No user IP repositories specified
INFO: [IP_Flow 19-2313] Loaded Vivado IP repository '/home/user/Xilinx/Vivado/2019.2/data/ip'.
antes del primer get files
WARNING: [Vivado 12-818] No files matched '/home/carlos/Desktop/digital_design/projects/ej01_ila_vio_v3/ej01_ila_vio_v3.srcs/sources_1/ip/ila_0_1/ila_v6_2/constraints/ila_impl.xdc'
ERROR: [Common 17-55] 'set_property' expects at least one object.
Resolution: If [get_<value>] was used to populate the object, check to make sure this command returns at least one valid object.
current_project ej01_ila_vio_v3


Si era un camino muerto, no llegué a enterarme, Federico me pasó esta receta, parece ser que por el locale debe estar cambiando la interpretación de algún caracter, quién sabe:



cd ~/Xilinx/Vivado/2019.2/bin
export LANG=en_US.utf8
export LC_ALL=en_US.utf8
./vivado


Para corregir el launcher, lo editás y ponés en command:


env LANG="en_US.utf8" LC_ALL="en_US.utf8" /opt/Xilinx/Vivado/2019.2/bin/vivado


Quizás alcance sólo con LC_ALL, pero ya se me acabó el tiempo para esa prueba.

 

Resumen

 

  • Configure display settings
  • Disable extra monitors
  • Start vivado
  • Reenable extra monitors


Algunos aprendizajes

 

No deseo spoilear el curso, tomalo, pero algunas cositas voy a comentar.

 

VIO e ILA

 

Son unos IP Cores que permiten hacer control y monitoréo desde la PC. En lugar de conectarles botones y leds, le conectás VIO y podés prender y apagar y ver los resultados. Con ILA podés obtener muestras de salidas, quizás no logra capturar todo pero medio que alcanza para saber si más o menos está haciendo lo que querés.

Si no tenés la placa y alguien te la presta de modo remoto, como ocurrió en este curso que nos habilitaron varias Arty-A7-35, es obvia la utilidad de este recuros. 

¿Para qué querrías hacer esto si tenés la placa?Esto lo exploraré mejor uno de estos días, es parte de mi TP.

No son gratis, ocupan un montón de espacio. Si mal no recuerdo ese manchón no estaba antes de desplegarlos.


VIO-ILA footprint
VIO-ILA footprint

Vivado tiene la opción de marcar con distintos colores los distintos componentes pero estoy muy cansado, ¿ya lo dije? Cuándo haga el TP probablemente lo muestre mejor.

 

 

Z


Otra cosa que aprendí es que internamente Z es mala palabra, me hubiese venido muy bien saberlo cuando quise hacer la cpu para el bit supervisor.



Refactorizaciones de MD5 en FPGA: 1 simulación

$
0
0

Este tema se parece a una cucaracha: la pisás y la dás por muerta, pero cuando volvés con la palita y la escoba a juntarla se cambió de lugar o incluso se escapó.


Tras todo lo aprendido en Basic Digital Design, propuse como trabajo práctico tomar este proyecto y aplicarle algunas mejoras.


Para ponerte al tanto podés ponerte a leer todo lo anterior o mejor contentarte con este resumen. De paso, me parece que es la primera vez que hago un diagrama decente del diseño.

Se trata de calcular el hash MD5 para una serie de valores con la intención de recuperar el valor original. Tal como está hecho alcanza para cuatro o cinco letras.

 

Esta no es exactamente la implementación original, es la que quedó tras lo que hice ahora, pero a grandes rasgos es la misma.

Con data_selector se elige uno de los hashes hardcodeados, con enable se inicia el proceso, cuando coincide el hash generado con el seleccionado, se detiene todo y en counter tenés el número aproximado al que generó el hash.

Diagrama conceptual
Diagrama conceptual



En realidad son ocho pipelines, así que este diagrama es más real. Fijate que el contador tiene tres bits menos, cada pipeline se instancia así:


pipeline pipeline0(.CLK(CLK),
  .counter_in({counter_out,3'b000}),
  .target_hash(target_selected),
  .reset(reset),
  .found(found0)
);

Los tres bits menos significativos están fijos para cada pipeline y corresponden a su índice.

Implementación 8 lanes
Implementación 8 lanes



La primera gran modificación fue simular. ¿Me podés creer que cuando hice esto no sabía simular y tuve que implementar la funcionalidades de avanzar el contador paso a paso y la de bajar la velocidad para poder ver que estaba ocurriendo?

La ventaja de este método "incorrecto" es que me obligó a pensar bastante e ingeniármelas para hacerlo funcionar.

Supuse que simular sería sencillo, pero no, aunque el circuito "funcionaba", al simular fallaba, no sé bien por qué ni me maté para comprenderlo, aunque estoy seguro de que el motivo era que durante los ciclos que los pipelines estaban inválidos hallaban algo espúreo y se ahí se detenía antes de tiempo. Tomé mi lista de tareas y las apliqué:

  • No aceptar como hallado mientras el pipeline estuviera "calentándose". Para esto agregué un nuevo contador que habilita la evaluación de hallado recién desde el momento en que llega a final del pipeline el primer valor válido.
  • Reemplazar la lógica de control pegada con moco por una FSM bien pensada.

 

Con warm up
Con warm up

 

No es exactamente como está en el diagrama, en lugar del and el warm_up_counter afecta el comportamiento de la FSM pero así tambien pudo haber funcionado.

No sólo anduvo la simulación como seda, sino que también la implementada.

Para simular lo que se puede hacer es crear un uno módulo por encima del top, que al crearlo le avisás a Vivado que va a ser un módulo de simulación.

 

En este, declarás regs y wires tal que reproduzcan las entradas y salidas respectivamente de la placa y le conectás el top que tenías,


`timescale 1ns/100ps

module tb_driver();
   reg  CLK;
   reg  reset_button;
   reg  enable_switch;
   reg  [3:0]target_switch;
   wire [7:0] SEG;
   wire [7:0] DIGIT;
   wire status_paused;
   wire status_running;
   wire status_warming;
   wire status_found;
   wire status_done;

always
  #5 CLK = ~CLK;
 
initial begin
  CLK  = 1'b0;
  reset_button  = 1'b1;
  enable_switch = 1'b0;
//target_switch = 4'b0000;
//target_switch = 4'b0001;  // 0000 0001
//target_switch = 4'b0010;  // 0000 0002
//target_switch = 4'b0011;  // 0000 0010
  target_switch = 4'b0100;  // 0000 0100
//target_switch = 4'b0101;  // 0000 1000
//target_switch = 4'b0110;  // 0001 0000


  # 200  reset_button  = 1'b0;
  # 200  enable_switch = 1'b1;
  # 1200 reset_button  = 1'b1;
  # 200  reset_button  = 1'b0;
  # 2000 $finish;
end

driver u_driver(
  .CLK            (CLK),      
  .CPU_RESETN     (reset_button),     
  .enable_switch  (enable_switch),     
  .target_switch  (target_switch),
  .SEG            (SEG),
  .DIGIT          (DIGIT),
  .status_paused  (status_paused),
  .status_running (status_running),
  .status_warming (status_warming),
  .status_found   (status_found),
  .status_done    (status_done)    
  );

endmodule

 

 

Con esta línea le estás diciendo que # de los que se ven más abajo equivalen a 1n y las fracciones 100ps.


`timescale 1ns/100ps


Con esto declarás las entradas y salidas, fijate que las entradas son registros, pues les vas a dar valores luego en el initial:


   reg  CLK;
   reg  reset_button;
   reg  enable_switch;
   reg  [3:0]target_switch;
   wire [7:0] SEG;
   wire [7:0] DIGIT;
   wire status_paused;
   wire status_running;
   wire status_warming;
   wire status_found;
   wire status_done;

 

Mirá la correspondencia con lo que hay en el xdc:

 
## Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {
    CLK }];
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports {
    CLK }];



## Switches

set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {
    enable_switch }];

set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {
    target_switch[0] }];
set_property -dict {PACKAGE_PIN R15 IOSTANDARD LVCMOS33} [get_ports {
    target_switch[1] }];
set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {
    target_switch[2] }];
set_property -dict {PACKAGE_PIN T18 IOSTANDARD LVCMOS33} [get_ports {
    target_switch[3] }];


## Leds

set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {
    running_led }];
set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS33} [get_ports {
    done_led }];
set_property -dict {PACKAGE_PIN J13 IOSTANDARD LVCMOS33} [get_ports {
    found_led }];


##7 segment display

set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports {
    SEG[7] }];
set_property -dict {PACKAGE_PIN R10 IOSTANDARD LVCMOS33} [get_ports {
    SEG[6] }];
set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {
    SEG[5] }];
set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports {
    SEG[4] }];
set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {
    SEG[3] }];
set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS33} [get_ports {
    SEG[2] }];
set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {
    SEG[1] }];
set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {
    SEG[0] }];

set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[0] }];
set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[1] }];
set_property -dict {PACKAGE_PIN T9  IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[2] }];
set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[3] }];
set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[4] }];
set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[5] }];
set_property -dict {PACKAGE_PIN K2  IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[6] }];
set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS33} [get_ports {
    DIGIT[7] }];


##Buttons


set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports {
    step_button }];
set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports {
    reset_button }];

 

 

 

Esto siginifica que cada 5 ns va a transicionar el clock, período de 10 ns, 100 Mhz:


always
  #5 CLK = ~CLK;

 

Estos son los estímulos que va a recibir la simulación, todo el primer bloque es simultáneo al cominezo, luego, va dejando pasar tantos ns como # diga:

initial begin
  CLK  = 1'b0;
  reset_button  = 1'b1;
  enable_switch = 1'b0;
//target_switch = 4'b0000;
//target_switch = 4'b0001;  // 0000 0001
//target_switch = 4'b0010;  // 0000 0002
//target_switch = 4'b0011;  // 0000 0010
  target_switch = 4'b0100;  // 0000 0100
//target_switch = 4'b0101;  // 0000 1000
//target_switch = 4'b0110;  // 0001 0000


  # 200  reset_button  = 1'b0;
  # 200  enable_switch = 1'b1;
  # 1200 reset_button  = 1'b1;
  # 200  reset_button  = 1'b0;
  # 2000 $finish;
end

 

 

Y finalmente, la instanciación del circuito, conectando a cada entrada o salida lo declarado antes:


 driver u_driver(
  .CLK            (CLK),      
  .CPU_RESETN     (reset_button),     
  .enable_switch  (enable_switch),     
  .target_switch  (target_switch),
  .SEG            (SEG),
  .DIGIT          (DIGIT),
  .status_paused  (status_paused),
  .status_running (status_running),
  .status_warming (status_warming),
  .status_found   (status_found),
  .status_done    (status_done)    
  );

endmodule


La simulación resultante:

 

 

Simulación
Simulación


Primero se desactiva el reset, luego se activa el enable, inmediatamente se pone en running y warming y empieza el contador, tras algunos ciclos finaliza warming y varios despues uno de los pipelines encuentra una coincidencia, se activan found y done, fin.


Me quedan unos defectos que no sé si resolveré pues tengo un tiempo limitado para presentar el trabajo práctico y además puedo mitigarlos "por software" más adelante:

  • Comprobar bien si los ciclos de warming son correctos
  • Puede estar relacionado, ver si encuentra los números bajos.
  • Ver que encuentre los números altos, es que el contador avisa que terminó antes de que se vacíe el pipeline, necesitaría un "cooling".
  • Se produce un offset entre lo hallado y el real y no hay información de cuál pipeline lo halló.

La solución por software para todos menos el último sería calcular los números bajos y los altos. Si los encuentra listo, no le pide nada al circuito pues ya los tiene.

Para el último sería tomar el valor y explorar los ocho posibles tras corregir el offset.

 

 

El código fuente de base y la simulación están en los tags base y simul respectivamente.

 




Refactorizaciones de MD5 en FPGA: 2 VIO

$
0
0

El contexto de esta nota está en la anterior.

Habiendo recuperado el proyecto y migrado a Vivado 2019.2 (cosa que me olvidé de mencionar antes) y hecho algunas correcciones y la simulación, la siguiente tarea es agregar VIO.

 

VIO es Virtual Input Output, un IP que te permite interactuar desde Vivado con la placa conectándole entradas y salidas virtuales, esto es muy útil para interactuar con una placa que no tiene leds, botones y switches, por ejemplo las que están en AWS. Si a esto le sumanos el programa hw_server, que permite "compartir" una placa en red, podemos tener la placa en casa y con un tunel ssh programarla y verla en acción desde afuera. Si le sumanos un par de dólares la hora, podemos probarlo en AWS, me han dicho que se hace así o similar, pero, otro día.

El escenario que más me habilita ahora es migrar de la Nexys4DDR que tiene 8 dígitos de siete segmentos, 16 leds, 16 switches y 5 botones a la PYNQ que tiene 4 leds, 2 switches y 4 botones o incluso a la Parallella, que tiene... nada.

De no utilizar VIO para poder interactuar con el circuito debería hacerlo vía AXI desde las CPUs de las ZYNQ (PYNQ y Parallella son ZYNQ), cosa que sé a un nivel muy elemental según he practicado en PYNQ en el 2020, pero es el objetivo final de esta seguidilla de pruebas, no nos adelantemos.

Pasamos de un una interfaz muy sencilla para ver en el resultado gracias a los 8 dígitos de 7 segmentos pero muy díficil de cambiar el hash a buscar, por ahora tengo unos precargados  que se seleccionan con 4 switches.

 

Para aplicar VIO hay que agregarlo con IP Catalog y definir sus características.

Recordá que los pasos que anoto acá son más un machete para mí que un tutorial para vos, así que no capturo paso a paso, blogger no es una buena herramienta para hacer esto, quizás junte ganas y haga un video en algún momento.


IP Catalog ->

Buscar VIO

Solapa General options
   Input probe count (en mi caso dos pues quiero separar el contador del estado)
   Output probe count

Solapa PROBE_IN ports
   ajustar cantidad de bits
Solapa PROBE_OUT ports
   ajustar cantidad de bits y valores iniciales


Observá que el input y output es respecto al VIO, es complementario a tus inputs y outputs.


Al igual que en el caso de la simulación, he optado por crear un nuevo top que instancie al existente en lugar de incorporar el VIO en el top original. De un modo u otro, en el template obtenés lo que hay que pegar en tu código:

 

Project manager
  sources
    IP
      vio_0
        instantation template
          vio_0.vho (VHDL)
          vio_0.veo (Verilog) 

 

vio_0 vio_driver (
 .clk(CLK),              // input  wire clk
 .probe_in0(probe_in0),  // input  wire [ 4 : 0] probe_in0
 .probe_in1(probe_in1),  // input  wire [31 : 0] probe_in1
 .probe_out0(probe_out0) // output wire [ 4 : 0] probe_out0
);

Customize IP
Customize IP

 

 

 

Salvo el clock y las entradas y salidas que quieras conservar de la placa, hay que eliminarlas del xdc y pasarlas al nuevo top. Dejé el botón de reset:


## Clock signal
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 }
      [get_ports {  CLK }];
create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5}
      [get_ports {  CLK }];

##Buttons
set_property -dict { PACKAGE_PIN C12   IOSTANDARD LVCMOS33 }
      [get_ports { CPU_RESETN }];



Podés conectar directamente probe_in y probe_out, pero si usás unos wires en el medio, luego la vista de VIO se dá cuenta y usa esos nombres, que es mucho más cómodo.

 

 

   wire [ 4 : 0] probe_in0;
   wire [31 : 0] probe_in1;
   wire [ 4 : 0] probe_out0;
  
   assign probe_in0  = { status_paused,
                         status_running,
                         status_warming,
                         status_found,
                         status_done };
   assign probe_out0 = { enable_switch, target_switch };
   assign probe_in1  = target;

 


Se puede apreciar que el VIO ocupa poco lugar:

 

VIO footprint
VIO footprint
 

 

Lo que cambia con respecto a la grabación normal es que en el diálogo ahora hay un archivo extra, que es el VIO:

 

 

Archivo extra
Archivo extra



 Así quedan las conexiones entre el top original y VIO:


VIO conectado
VIO conectado
 

Esa diferencia entre [29:0] y [31:0] en counter es por que, recordá, los tres bits menos significativos no son parte del contador, dependen de a que pipeline nos estemos refiriendo, así que le ponemos 0:

 

assign target = {counter_out,3'b000};

 

Esa característica me hizo perder varias horas pues la adaptación la estaba haciendo en el VIO en lugar de lo más cerca posible de la diferencia: lección, hay que ser lo menos inteligente posible, si hay algo raro, debe ser lo más reducido posible.

Para comprender y corregir, tuve que volver un paso atrás a simular, pero sin el VIO, sólo con el cambio que éste había producido. Queda pendiente simular con VIO si es que es posible.

En algún momento haré que se pongan los tres bits del pipeline que lo halló.

Al descargar el bitstream se abre un dashboard que desaparece si te vas al Project Manager, pero regresa si volvés a Program & Debug.

VIO en acción
VIO en acción

 


Si no hubiera puesto los wires que mencioné antes, diría probe_xxx, menos legible.


El mensaje original es 0xBEBACAFE, pero tal como he mencionado, este diseño trae un valor cercano, me falta investigar bien esa diferencia para compensarla, pero para elllo, necesito pasar al siguiente nivel, sacarle realmente el jugo al VIO, voy a prescindir del selector de hashes e ingresar hashes arbitrarios... en la próxima entrada.

El código en github

 




Refactorizaciones de MD5 en FPGA: 3 VIO total

$
0
0

Veníamos de reemplazar algunos switches y leds por VIO.

Llegó el momento de hacer que este juguete sea más productivo, para eso hace falta poder ingresar hashes arbitrarios en pocos segundos o menos en lugar de regenerar el bitstream en decenas de minutos.

La idea es eliminar el selector de hashes hardcodeados e ingresar el hash a buscar de alguna manera. Sería bastante complicado hacerlo físicamente, habría que conectar 128 switches o ir cargando por tandas, demasiado trabajo y muy fácil equivocarse al cargar.

Pero, ¿qué son 128 switches virtuales, que además entienden hexadecimal? Gracias a VIO puedo ahorrarme la interfaz de usuario.

Aunque mucho mejor que la opción física, para probar muchos valores es un tanto tedioso, luego exploraré interactuar programáticamente con el VIO y así poder testear no una simulación sino la realidad misma.

Primero lo primero, el VIO manual.

 

VIO total
VIO total


Hay que quitar los selectores y enchufarle el VIO a la entrada de los hashes.

 

Para modificar el VIO hay que hacerle doble click al xci:

Seleccionar el xci
Seleccionar el xci


Y ajustar los nuevos valores:


Nueva probe
Nueva probe, fijate como me equivoqué con ese 127


 

También hay que cambiar la interfaz del driver tambien, antes entraban cuatro bits, ahora son 128 en su lugar.

Los assign para que VIO muestre nombres útiles:


   wire [   4 : 0] probe_in0;
   wire [  31 : 0] probe_in1;
   wire [   4 : 0] probe_out0;
   wire [ 127 : 0] probe_out1;

   assign probe_in0  = {
            status_paused,
            status_running,
            status_warming,
            status_found,
            status_done
   };
   assign probe_out0 = enable_switch;
   assign probe_in1  = target;
   assign probe_out1 = target_selected;

 

La nueva interfaz del VIO:


vio_0 vio_driver (
 .clk(CLK),               // input wire clk
 .probe_in0(probe_in0),  // input wire [4 : 0] probe_in0
 .probe_in1(probe_in1),  // input wire [31 : 0] probe_in1
 .probe_out0(probe_out0),// output wire [0 : 0] probe_out0
 .probe_out1(probe_out1) // output wire [127 : 0] probe_out0
);

Recordá que es output respecto al VIO, va a un input del diseño.

La nueva interfaz del driver:


driver u_driver(
  .CLK            (CLK),      
  .CPU_RESETN     (CPU_RESETN),     
  .enable_switch  (enable_switch),     
  .target_selected(target_selected),
  .target         (target),
  .status_paused  (status_paused),
  .status_running (status_running),
  .status_warming (status_warming),
  .status_found   (status_found),
  .status_done    (status_done)    
  );

Hasta acá parecía fácil, pero cuando estaba corrigiendo el ancho de VIO se cerró Vivado y aunque luego lo corregí y parecía todo ok, de modo efectivo quedó de 127 bits en lugar de 128. O mejor dicho, aceptó el assign probe_out1 = target_selected pero lo tomó de 127 bits y me dejó uno aparte, si hubiera sido el más significativo pude haber lidiado pero al ser el menos significativo rompe toda la representación hexadecimal.


Tuve que pedirle "Regenerate Output Products" en Design Runs pero los tomó de la cache:

 

Cached
Cached

Tiré la IP y volvíendolo a incorporar nuevamente me ignoró hasta que encontré como limpiar la cache, en particular vía GUI:

  • Project manager
  • Settings
  • IP
  • IP Cache
  • Clear Cache

Y...

no, falló.

Pensé que era por el assign, lo quité.

Tiré todo el proyecto salvo los .v y el xpr

Partí el probe en dos de 64 bits...

Ok, anda, hora de ver el manual. Virtual Input/Output v3.0 LogiCORE IP Product Guide (PG 159) no es, sólo explica el IP, obvio, el problema está en Vivado logic analyzer, cuya documentación en un framentito de Vivado Design Suite User Guide: Programming and Debugging (UG 908) desde la página 205, no veo nada que indique esa limitación.

Como sea, debido a ese error del comienzo, no sé si Vivado quedó "contaminado" o justo accidentalmente hay una limitación o bug que impide manipular un probe de 128 bits.

Quedó todo muy parecido a lo expuesto anteriormente, salvo que en lugar de un probe de 128 bits tengo dos de 64, no me quita el sueño.

   wire [ 4 : 0] probe_in0;
   wire [31 : 0] probe_in1;
   wire [ 4 : 0] probe_out0;
   wire [ 63 : 0] probe_out1;
   wire [ 63 : 0] probe_out2;
  

vio_0 vio_driver (
  .clk(CLK),                // input wire clk
  .probe_in0(probe_in0),    // input wire [4 : 0] probe_in0
  .probe_in1(probe_in1),    // input wire [31 : 0] probe_in1
  .probe_out0(probe_out0),  // output wire [0 : 0] probe_out0
  .probe_out1(probe_out1),  // output wire [63 : 0] probe_out1
  .probe_out2(probe_out2)   // output wire [63 : 0] probe_out2
);

driver u_driver(
  .CLK            (CLK),      
  .CPU_RESETN     (CPU_RESETN),     
  .enable_switch  (enable_switch),     
  .target_selected({probe_out1,probe_out2}),
  .target         (target),
  .status_paused  (status_paused),
  .status_running (status_running),
  .status_warming (status_warming),
  .status_found   (status_found),
  .status_done    (status_done)    
  );


Veamos la secuencia completa de un reset por placa, cargar el hash en el VIO, ejecución y hallazgo.

Reset, el circuito está en modo "paused", target en cero.

reset
reset


Tras ingresar en la consola tcl los comandos:

set_property OUTPUT_VALUE d96ff7938f84d310 [get_hw_probes probe_out1 -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
commit_hw_vio [get_hw_probes {probe_out1} -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
set_property OUTPUT_VALUE c9d25805bfdbabb2 [get_hw_probes probe_out2 -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]
commit_hw_vio [get_hw_probes {probe_out2} -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"vio_driver"}]]


queda el valor del hash en probe_out1 y probe_out2:


hash cargado
hash cargado

Al oprimir en VIO enable_switch, pasa al estado "running" tras un efímero "warming":


buscando
buscando

Como halla el valor, queda en "done" y "found":


hallado
hallado

Fijate que el valor es el esperado "BEBA_CAFE" + 0x220, pronto lidiaremos con ello.

El código en github




Refactorizaciones de MD5 en FPGA: 4 algunos arreglitos

$
0
0

Venís de poder ingresar hashes arbitrarios.


Ajustes de los probes

Había dicho que el haber partido el probe de 128 bits en dos de 64 no me quitaba el sueño y habrás pensado que había algo más.

Pues si, tengo en mi desván mental la idea de AXI <=> 32 bits, así que escarbé superficialmente y en algún manual encontre que:

 ARM expects that:

    the majority of components use a 32-bit interface

    only components requiring 64-bit atomic accesses use a 64-bit interface.
 


y no veo motivo para contrariar a ARM, así que partir los 128 en cuatro de 32 medio que estaba en mis planes, sólo me quedó el resentimiento de no haber podido comprender si VIO/Logic Analyzer no se llevan bien con 128 bits o fue a raiz de mi error que no pude usar un probe de 128 bits, eso está en la entrada anterior, olvidémoslo.

Sintetizando, voy a partir en cuatro los 128 bits porque parece ser lo más sencillo para el futuro, que no sé si llegará.

De paso, para poder automatizar toda la interacción, pase el botón de reset a VIO, una pena, me gustaba usar el botón del reset de la CPU...

Partido en cuatro:

// virtual inputs
   wire           enable_switch;
   wire           reset_switch;  
   wire [  4 : 0] probe_in0;
   wire [ 31 : 0] probe_in1;
   wire [  1 : 0] probe_out0;
   wire [ 31 : 0] probe_out1;
   wire [ 31 : 0] probe_out2;
   wire [ 31 : 0] probe_out3;
   wire [ 31 : 0] probe_out4;
  
// VIO patching
   assign probe_in0  = { status_paused,
                         status_running,
                         status_warming,
                         status_found,
                         status_done
                       };
   assign probe_out0 = { reset_switch,
                         enable_switch
                       };
   assign probe_in1  = target;
  

vio_0 vio_driver (
  .clk(CLK),                // input wire clk
  .probe_in0(probe_in0),    // input wire [4 : 0] probe_in0
  .probe_in1(probe_in1),    // input wire [31 : 0] probe_in1
  .probe_out0(probe_out0),  // output wire [0 : 0] probe_out0
  .probe_out1(probe_out1),  // output wire [31 : 0] probe_out1
  .probe_out2(probe_out2),  // output wire [31 : 0] probe_out2
  .probe_out3(probe_out3),  // output wire [31 : 0] probe_out3
  .probe_out4(probe_out4)   // output wire [31 : 0] probe_out4 
);


Testing con Tcl

Dejando de lado la simulación, para testear sobre todo al comienzo utilicé métodos muy cavernícolas, directamente sobre la placa, usando la opción de avanzar el contador de a un paso con un botón y me parece que tambien inspeccionando con los 8 dígitos de 7 segmentos estados intermedios.

Ahora, con VIO, puedo tanto con la GUI interactuar de modo más sencillo y el valor resultante copiarlo y pegarlo en lugar de transcribirlo a mano, un cierto progreso.

Pero seguiría siendo un cavernícola... mejor digo, siendo un cavernícola, voy a pasar de la Edad de Piedra a la Edad de Bronce e interactuar con VIO usando la consola Tcl, desde la cual puedo ejecutar scripts tanto con comandos como con lógica.

Lo primero es descifrar cómo se lee y escribe, que es muy sencillo, en Vivado Design Suite User Guide: Programming and Debugging (UG 908) desde la página 205 hay algunas explicaciones y además mirando lo que Vivado va ejecutando en la consola no podés dejar de entender algo, sólo que lleva un tiempito.

Por ahora y quizás por siempre, no me interesan los detalles y el protocolo subyacente, lo usaré tipo caja negra. Mi POC consiste en poder ejecutar un ciclo completo de reset, cargar hash, habilitar, deshabilitar, evaluar si fué hallado y mostrarlo.

El formato de este blog no es el mejor para mostrar las sucesivas refactorizaciones, agradeceré tu mejor esfuerzo.

Si es tu primer contacto con Tcl:

set variable valor  equivale a variable = valor 

set variable1 $variable2  equivale a variable1 = variable2

funcion arg1 arg2 equivale a funcion(arg1, arg2)

set var [ funcion arg1 arg2 ] equivale a var = funcion(arg1, arg2)

En general, la clave de entender Tcl es que son todas funciones, incluido el set, if, while:

while condicion acción : la función while recibe dos argumentos.

 

Con respecto a {}, yo sabía programar bastante bien en Tcl, pero eso fue hace 20 años y para esto no necesito recuperar tanto, así que no estoy en condiciones de explicarlo responsablemente. Podés RTFM y ver la previous y next lesson. Si más o menos sabés programar en dos o tres lenguajes, tu sistema de pattern recognition seguramente te permitirá entender todo lo que sigue.

Versión base

En esta versión, pegué todo el código sin mayor pensamiento en escalabilidad:


# Deshabilitar el contador

set_property OUTPUT_VALUE 0 [get_hw_probes enable_switch]
commit_hw_vio [get_hw_probes {enable_switch}]
 

# Apretar y soltar el botón de reset


startgroup
set_property OUTPUT_VALUE 0 [get_hw_probes reset_switch]
commit_hw_vio [get_hw_probes {reset_switch}]
endgroup

startgroup
set_property OUTPUT_VALUE 1 [get_hw_probes reset_switch]
commit_hw_vio [get_hw_probes {reset_switch}]
endgroup


# Cargar las cuatro partes del hash

set_property OUTPUT_VALUE 2d1bbde2 [get_hw_probes probe_out1]

commit_hw_vio [get_hw_probes {probe_out1}]

set_property OUTPUT_VALUE acac0afd [get_hw_probes probe_out2]
commit_hw_vio [get_hw_probes {probe_out2}]

set_property OUTPUT_VALUE 07646d98 [get_hw_probes probe_out3]
commit_hw_vio [get_hw_probes {probe_out3}]

set_property OUTPUT_VALUE 154f402e [get_hw_probes probe_out4]
commit_hw_vio [get_hw_probes {probe_out4}]

# Habilitar el contador

set_property OUTPUT_VALUE 1 [get_hw_probes enable_switch]
commit_hw_vio [get_hw_probes {enable_switch}]

set status_done 0

while {$status_done == 0} {

      # Leer el valor de status_done

    refresh_hw_vio [get_hw_vios {hw_vio_1}]
    set status_done [ get_property INPUT_VALUE [get_hw_probes status_done] ]
    after 1000
}

      # Leer el valor de status_found

set status_found [ get_property INPUT_VALUE [get_hw_probes status_found] ]


if {$status_found == 1} {

      # Leer el valor hallado

    refresh_hw_vio [get_hw_vios {hw_vio_1}]
    set result [ get_property INPUT_VALUE [get_hw_probes target] ]
    puts $result
} else {
    puts "Not found"
}

# Deshabilitar el contador


set_property OUTPUT_VALUE 0 [get_hw_probes enable_switch]
commit_hw_vio [get_hw_probes {enable_switch}]


Primera refactorización: procedures


Tenemos un nuevo elemento, proc, que recibe tres argumentos: nombre del procedimiento, argumentos y código a ejecutar.

Con respecto a startgroup/endgroup, me desasné en UG 835 Vivado Design Suite TclCommand Reference Guide, del cual no tengo link, pues para variar usé "Documentation Navigator", una simpática aplicación que te permite buscar documentación y en el caso de los pdf te muestra la última versión y opcionalmente anteriores y te los va bajando a ~/Documents/XilinxDocs/Vivado/documentation/sw_manuals/xilinx2019_2, en este caso. Me imagino que depende de lo que bajes en lugar de 2019_2 dirá otra cosa.

Me resulta medio raro no tener bajados los archivos junto al resto de los miles de manuales, pero es bastante cómodo, creo que voy a tirar un symlink para tener lo mejor de los dos mundos.

Volviendo a xxxgroup, viene a ser parece para hacer transacciones reversibles, por ahora las voy a dejar, pero en la próxima iteración probaré quitarlas.

 

proc reset {} {
    startgroup
    set_property OUTPUT_VALUE 0 [get_hw_probes reset_switch]
    commit_hw_vio [get_hw_probes {reset_switch}]
    endgroup

    startgroup
    set_property OUTPUT_VALUE 1 [get_hw_probes reset_switch]
    commit_hw_vio [get_hw_probes {reset_switch}]
    endgroup
}

proc disable {} {
  set_property OUTPUT_VALUE 0 [get_hw_probes enable_switch]
  commit_hw_vio [get_hw_probes {enable_switch}]
}

proc enable {} {
  set_property OUTPUT_VALUE 1 [get_hw_probes enable_switch]
  commit_hw_vio [get_hw_probes {enable_switch}]
}

proc writeHash {hash1 hash2 hash3 hash4} {
  set_property OUTPUT_VALUE $hash1 [get_hw_probes probe_out1]
  commit_hw_vio [get_hw_probes {probe_out1}]

  set_property OUTPUT_VALUE $hash2 [get_hw_probes probe_out2]
  commit_hw_vio [get_hw_probes {probe_out2}]

  set_property OUTPUT_VALUE $hash3 [get_hw_probes probe_out3]
  commit_hw_vio [get_hw_probes {probe_out3}]

  set_property OUTPUT_VALUE $hash4 [get_hw_probes probe_out4]
  commit_hw_vio [get_hw_probes {probe_out4}]
}

proc readStatus {} {
  refresh_hw_vio [get_hw_vios {hw_vio_1}]
  return [ get_property INPUT_VALUE [get_hw_probes status_done] ]
}

proc readFound {} {
  refresh_hw_vio [get_hw_vios {hw_vio_1}]
  return [ get_property INPUT_VALUE [get_hw_probes status_found] ]
}

proc readResult {} {
  refresh_hw_vio [get_hw_vios {hw_vio_1}]
  return [ get_property INPUT_VALUE [get_hw_probes target] ]
}

#inicio

reset

disable

writeHash 2d1bbde2 acac0afd 07646d98 154f402e

enable

set status_done 0

while {$status_done == 0} {

    set status_done [ readStatus ]
    after 1000
}

set status_found [ readFound ]


if {$status_found == 1} {
    set result [ readResult ]
    puts [ readResult ]
} else {
    puts "Not found"
}


disable

 

Segunda refactorizacion: más usable

Evité repeticiones y toma el hash en una sola pieza:


proc readProbe {pin} {
  refresh_hw_vio [get_hw_vios {hw_vio_1}]
  return [ get_property INPUT_VALUE [get_hw_probes $pin] ]
}

proc writeProbe {value pin } {
    set_property OUTPUT_VALUE $value [get_hw_probes $pin]
    commit_hw_vio [get_hw_probes ${pin}]
}

proc reset {} {
  writeProbe 0 reset_switch
  writeProbe 1 reset_switch
}

proc disable {} {
  writeProbe 0 enable_switch
}

proc enable {} {
  writeProbe 1 enable_switch
}

proc writeHash {hash} {
  writeProbe [ string range $hash  0  7 ] probe_out1
  writeProbe [ string range $hash  8 15 ] probe_out2
  writeProbe [ string range $hash 16 23 ] probe_out3
  writeProbe [ string range $hash 24 31 ] probe_out4
}

proc readResult {} {
  return [ readProbe target]
}

proc isDone {} {
  return [ readProbe status_done ]
}

proc isFound {} {
  return [ readProbe status_found ]
}

reset

disable

writeHash 2d1bbde2acac0afd07646d98154f402e

enable

while { ! ( [ isDone ] ) } {
    after 1000
}

if { [ isFound ] } {
    puts [ readResult ]
} else {
    puts "Not found"
}

disable

 

Lo próximo será utilizar el código anterior para ejectuar muchas búsquedas para valores interesantes y así ver si hay errores (los hay en los extremos) y ajustar correctamente el valor obtenido:


El código en github



 

Agujeros analógicos para preservación de webinares.

$
0
0

Los webinars existian desde antes que el covid, pero no les prestaba mucha atención por que prefiero las actividades presenciales. Como el covid prefiere los webinars, en este último año tuve que desarrollar algunos métodos y programas, no sólo para webinars sino para remoto en general, como xzoom y usar dos máquinas a la vez.

Una comodidad que presentan, cuando quedan grabados es poder "asistir" aunque tengas un conflicto horario. A veces se pueden bajar y otras no y el problema es que no me gusta mucho quedar sujeto a la voluntad de quien pueda dejar de publicar la grabación.

Dado que no nos importa mucho la calidad pues lo que nos interesa son los conceptos, vamos a explotar lo que se llama el agujero analógico que básicamente dice algo así como:

No importa cuánto ni cómo intentes proteger un contenido multimedia digital, siempre alguien puede rompértelo con una cámara y un micrófono.

Con respecto a la grabación en vivo es muy sencillo se hace con recordmydesktop, tengo unos scripts facilitadores en github, los que dicen record pero no timer, podés elegir grabar la ventana entera o de un modo un tanto indirecto un área.

El que graba por id de ventana te pide que le señales cuál y lo hace.

El que es por área, determina un área de una ventana de referencia que despues quitás. Es útil para grabar parte de una ventana, como suele ser un proyector.

Uso de máscara para recordmydesktop
Uso de máscara para recordmydesktop


En la imagen podés ver que estoy usando una terminal que tiene transparencia total para poder ver que hay debajo, hace de máscara.

Si los probás un poquito vas a llegar a la conclusión de que en realidad el que graba por área es prescindible, pero sirve para cuando querés tener el comando listo.


Hasta donde yo sé usar recordmydesktop y configurar audio, no he podido que este grabe sólo el audio del video que está grabando y esto es por que no tiene relación con la aplicación a la que está grabando, a tal punto que si le ponés otra ventana encima grabará a ésta última, recordmydesktop interactúa con xwindows y graba todo el audio. Para ello con Linux Mint Mate en Sound Preferences pongo como Input a "Monitor of ...." según a donde esté yendo el audio.

Tendría que explorar pulseaudio o lo que sea que tengas de audio para mejorar este specot o mejor me quedo con mantener la disciplina de no activar ningún otro audio mientras y además recordar no cambiar de desktop ni abrir nada nuevo que pueda aparecer encima de la región grabada.

Queda entonces muy limitada la grabación en vivo haciendo otra cosa, aunque no es imposible.

Ponele que ya tenés tu copia para futura referencia, perfecto, pero había dicho antes que quizás tenías un conflicto horario. Supongamos que estás presente con una compu pero no podés asistir, podrías grabarlo.

Nos queda grabar la grabación, que nos trae otro problema, el de cuándo terminar. Si estamos viendo a la vez o cuidadosamente haciendo otra cosa, vemos que terminó y listo, pero si nos fuimos a hacer otra cosa, va a seguir grabando luego de haber terminado la sesión.

Para esto agrego un nuevo script. Lo que hace es iniciar la grabación y la manda al background. Espera un tiempo determinado y le envía un control-C para que deje de grabar, notá que ahora sabemos cuál es la duración del video pues es una grabación.

Para enviarle el control-C, necesitamos conocer el pid.

La primera tentación se usar 

ps ax | grep recordmydesktop | cut -d"" -f1
3412

pero me ofende, es hora de progresar, usemos 

pidof recordmydesktop
3419

que es lo mismo pero más elegante.

Ambas soluciones tienen un problema, improbable pero posible, que es que haya más de una instancia de recordmydesktop en ejecución y no tenemos manera de saber cuál es la correcta.

Lo podemos arreglar con:

ps | grep recordmydesktop | cut -d"" -f2


  PID TTY          TIME CMD
 3473 pts/22   00:00:00 bash
 3486 pts/22   00:00:00 recordmydesktop
 3507 pts/22   00:00:00 ps
 4993 pts/22   00:00:00 bash

 

Pero ya estamos viendo que ese espacio adelante de ps que no está en ps ax nos va a traer problemas.

Necesitamos obtener el pid del que acabamos de ejecutar.

Como lo ejecutamos con & para mandarlo al background, podemos consultarlo con jobs -p, pero otra vez tenemos el conflicto de que pueden haber más jobs ejecutándose en este mismo proceso, aunque tambien improblable. Vamos a usar éste método quedándonos con el último job:

./script.sh &
jobs -p | tail -1
3491


¿Cómo viene el script?

  • iniciar grabación en background
  • obtener el pid
  • esperar nn segundos

Esto es con sleep segundos, por ejemplo para un video de 44:32:

sleep 2672

y sólo falta mandarle el control-C


 /bin/kill --table
 1 HUP      2 INT     3 QUIT   4 ILL     5 TRAP
 6 ABRT     7 BUS     8 FPE    9 KILL   10 USR1
11 SEGV    12 USR2   13 PIPE  14 ALRM   15 TERM
16 STKFLT  17 CHLD   18 CONT  19 STOP   20 TSTP
21 TTIN    22 TTOU   23 URG   24 XCPU   25 XFSZ
26 VTALRM  27 PROF   28 WINCH 29 POLL   30 PWR
31 SYS
    


Fijate que uso /bin/kill, esta es la versión por id:

TIME=$(( $1 * 60 + $2 ))
echo "Select which window to record"
echo "Press CRTL-C to cancel"
echo
ID=$( xwininfo | grep "Window id" \
               | cut -d : -f 3 | cut -d"" -f 2 )
echo "Recording $1:$2 ($TIME seconds)"
echo "Press CRTL-C to stop recording"
echo -n "Starts in 5 "
sleep 5

recordmydesktop --windowid=$ID &
RMDPID=$( jobs -p | tail -1 )

sleep ${TIME}
/bin/kill -2 ${RMDPID}


Esta por área:


TIME=$(( $1 * 60 + $2 ))
echo "Put a window over the area that you want to record and select it"
echo "Press CRTL-C to cancel"
echo

INFO=$( xwininfo  )

WIDTH=$( echo "$INFO" | grep Width: | cut -d "" -f 4 )
HEIGHT=$( echo "$INFO" | grep Height: \
                       | cut -d "" -f 4 )
X=$( echo "$INFO" | grep "Absolute upper-left X"
                  | cut  -d "" -f 7 )
Y=$( echo "$INFO" | grep "Absolute upper-left Y"
                  | cut  -d "" -f 7 )
echo "Recording $1:$2 ($TIME seconds)"
echo "Press CRTL-C to stop recording"
echo -n "Starts in 5 "
sleep 5

recordmydesktop -x "$X" -y "$Y" --width "$WIDTH" \
                --height "$HEIGHT"&
RMDPID=$( jobs -p | tail -1 )

sleep ${TIME}
/bin/kill -2 ${RMDPID}

 

No te olvides de desactivar el screensaver o al menos darle un tiempo tal que no se active antes de tiempo.


Todo  en github.



 

 




Orden y scripting para gestionar y preservar webinares

$
0
0

 Venís de leer cómo grabar webinares, pero te falta el antes y el despues.

 

Cómo conseguir webinares

 

Aunque claramente tengo un sesgo hacia algunos temas igual te cuento.

Con el dork "site:PROVEEDOR.com webinar" conseguís donde están los webinares de tus proveedores de preferencia.

Te pego acá algunos, no necesariamente los he explorado pero a ojo,  por los que he asist, ido parecen ser los correctos:

https://www.xilinx.com/about/webinar.html

https://www.nxp.com/design/training:TRAINING-EVENTS#/

https://www.arm.com/company/events/on-demand-webinars

https://neo4j.com/webinars/

etc...

Si te pareció medio raro eso de que nos los exploré, es por que mi fuente principal proviene de recibir por mail los eventos, habiéndome registrado en diversas listas, que corresponden a esos mismos proveedores.

Esto no es buscar oro, en realidad vos sos el producto así que apenas demuestres interés te van a llegar de sobra.

 

Cómo guardar y ordenar webinares


El concepto de ordenamiento es algo muy personal, así que lo que te comparto es sólo como referencia para que lo adaptes a tu gusto. De paso, hace bastante que no explico bash, aprovecho la ocasión así repasamos un poquito.

Todo esto es válido si compartís conmigo la perversa perversión de no confiar en la nube e intentar tener copia de lo que pueda tener valor.

Lo que más útil me ha resultado es distinguir los ya atendidos de los que no. Luego los que tengo de los que no. Ya tenemos cuatro posibilidades. Si a eso se le agrega que a algunos tanto atendidos como no, les estoy esperando el link para verlo y de paso  quizás grabarlo y algunos que... mejor te muestro las categorías que me vienen resultado:


  • attended
  • to_attend
  • to_classify
  • to_download
  • to_download_and_attend
  • to_download_and_attend_waiting_link

Entonces, para cada proveedor, tengo una carpeta con esta estructura adentro.

  • ARM
    • attended
    • to_attend
    • to_classify
    • to_download
    • to_download_and_attend
    • to_download_and_attend_waiting_link
  • XILINX
    • attended
      • webinar 1 
        • video 1.ogv
        • material 1.tgz
    • to_attend
    • to_classify
    • to_download
    • to_download_and_attend
    • to_download_and_attend_waiting_link


Dentro de cada categoría, una carpeta con el nombre del webinar conteniendo el video y opcionalmente:

  • preguntas y respuestas.pdf
  • material adicional.tgz

Parecería que vamos bien, pero teniendo más de tres proveedores se empieza a tornar confuso, ¿cúales ví? ¿cuáles tengo que bajar? Para eso están los scripts.

El primero está implícito y es cómo agregar un nuevo proveedor, por ejemplo, Xilinx:

cp -r template XILINX

El segundo es para explorar:

  1. for CAT in "to_attend""to_download" \
  2.       "to_download and attend"  \
  3.       "to_download and attend waiting link" \
  4.       "to_download waiting link""to_classify"; do
  5.    echo "#########################################"
  6.    echo "$CAT"
  7.    find . -path "*/$CAT/*" -type d  \
  8.       | rev \
  9.       | cut -d"/" -f 1 \
  10.       | rev \
  11.    | while read WEBINAR; do
  12.      echo \
  13.      $(find . -iname "$WEBINAR" | cut -d "/" -f 2)\
  14.      " $WEBINAR"
  15.    done
  16.    echo
  17. done


En la línea 1 a la 4 tenemos un for, que es un loop que va ejecutar la sección entre el do de la 4 y el done de la 17, asignando a CAT los strings enumerados.

Podría tomar esas categorías de la carpeta de template descartando to_attend, pero prefiero tener el control sobre el orden de las categorías.

Las líneas 5 y 6 hacen de encabezado de categoría.

En la 7 tenemos que vamos a buscar en la carpeta actual, los paths que coincidan en su nombre con CAT entre "/" y que sean directorios. Es que nos interesa la carpeta contenedora del webinar, no el video ni los materiales adicionales.

El problema es que nos trae algo de la forma:

./PROVEEDOR/CAT/webinar

y sólo nos interesa el webinar. En las líneas 8 a 10 tomo lo que haya a la derecha del último "/"

Primero lo reversamos con rev, luego con cat con delimitador "/" pedimos el primer campo (o sea el último al dercho) y lo volvemos a reversar.

Con el while de la 11, vamos leyendo cada resultado y asignándolo a WEBINAR y ejecutando el bloque do...done. Al WEBINAR lo buscamos en la 13 y con el cut nos quedamos con el primer campo, que es el PROVEEDOR.

Eso se lo damos al echo con $( ) que le agrega el WEBINAR y finalmente nos queda de la forma:

################################################
CAT1
PROVEEDOR1 WEBINAR1
PROVEEDOR1 WEBINAR2
PROVEEDOR2 WEBINAR3

################################################
CAT2

################################################
CAT3
PROVEEDOR1 WEBINAR4
PROVEEDOR3 WEBINAR5
PROVEEDOR4 WEBINAR6



Cuando lo hice no tenía clara la estructura aún, asi que este script puede tener alguna tara debida al legacy, seguro que lo podría mejorar, pero prefiero usar ese tiempo en escribir y compartir el tema

 

Cómo compartir conmigo los webinares

 

El paso final tiene que con que yo suelo ver los webinares en una tablet cuando estoy fuera de casa, poco frecuente con la cuarentena pero ocurre.

Lo primero es generar symbolic links a los videos que hayan en "to_attend" de todos los proveedores en una sola carpeta:

 

  1. find . -path "*/to_attend/*" \
  2.      -iname "*ogv" -o -iname "*mp4" \
  3.    | while read WEBINAR; do
  4.       ln -s "../$WEBINAR" zone4transfer
  5. done

En la línea 1 buscamos en las carpetas "to_attend" archivos ogv o mp4 y para cada uno hallado, generamos en la 3 el symbolic link con ln dentro de la carpeta que luego compartiremos.


Lo segundo, opcional, es cambiarle el nombre a los links, por ejemplo para un orden para verlos prefijando con 01_, 02_, lo que sea


Lo tercero es servirlos vía web, mi tablet tiene un montón de años, ya le cambié el conector USB y se ha roto otra vez y no puedo transferir archivos y me molesta usar una SD card.

  1. find zone4transfer -iname "*.mp4" \
  2.   -o -iname "*.pdf" \
  3.   -o -iname "*.ogv" \
  4.   | sort \
  5.   | while read FILE; do
  6.   FILE=$( basename "$FILE" )
  7.   echo "<a href=\"./$FILE\">$FILE</a><br/>"
  8. done  >zone4transfer/index.html
  9. php -t zone4transfer -S \
  10. $( ip addr show dev enp3s0 \
  11.    | grep "inet " \
  12.    | cut -d "" -f 6 \
  13.    | cut -d "/" -f 1\
  14. ):8080

En las líneas 1 y 2 buscamos en la carpeta donde están los symlinks los archivos mp4, ogv y de paso pdf, sirve para otras transferncias.

En la 3 le damos orden, en la 4 vamos leyendo y asignándola a FILE, pero tenemos que quitarle la ruta completa, en la 5 con basename, que por algún motivo oscuro no lo usé con el mismo propósito en el primer script.

En la 6 generamos una referencia html y en la 7 las concatenamos en un index.html

De la 9 a la 12 obtenemos la dirección IP de la interfaz sobre la que vayas a compartir y le concatenamos en la 13 el puerto.

Finalmente, en la 8 lanzamos un servidor web de php para que sirva en la ip y puerto que definimos antes los archivos de la carpeta donde están los symlinks.

Y más finalmente, si tenés un Android 4.x como el de mi tablet, te bajás VLC y podés ver los videos.

 

Algunas explicaciones pendientes

 

Fijate que "\" indica continuación de la línea en la siguiente, ojo, no puede tener nada a continuación salvo el salto de línea.

El comando find es bastante molesto, necesita que le respetes el orden de lo que le vas dando, es de mucho antes de expresiones como las de búsqueda de mongo, que aunque complicadas terminan siendo intuitivas. El -o significa "o".


El código en https://github.com/cpantel/playground/tree/master/sysadmin/webinar







Teclado Hexadecimal USB

$
0
0
A raiz de mi cada vez mayor involucramiento con sistemas embebidos y fpga y un arrastre de hace años de networking, tengo una necesidad: ingresar letras de la "a" a la "f" para cosas como código de máquina, direcciones de memoria y direcciones MAC, o sea, datos en formato hexadecimal.

¿Qué es eso? Pues que las máquinas representan todo con unos y ceros, pero a las personas nos cuesta, rápido, decime cuál número es mayor:

10111110101110101100101011111110

10111110101100001100101011111110



Esos números son

3199912702

3199257342


Que no es el formato nativo de la compu pero si nuestro.

Si esos números los agrupamos:

1011 1110 1011 1010 1100 1010 1111 1110

1011 1110 1011 0000 1100 1010 1111 1110


Vemos que cada grupo va de 0000 a 1111, que son 16 combinaciones y podemos representar con 0 a 9 y seis caracteres más, arbitrariamente elegidos A a F:

 0   0
 1   1
 2   2
 3   3
 4   4
 5   5
 6   6
 7   7
 8   8
 9   9
10   A
11   B
12   C
13   D
14   E
15   F


Podemos reescribir así:

BEBACAFE

BEB0CAFE


No es nuestro formato nativo, es fácil de convertir a y desde binario y es más fácil leerlos y escribirlos sin equivocarse.

No voy a entrar en todos los detalles de este tema que se llama "sistemas numéricos".


Cuando son pocos caracteres, aunque incómodo no es tan terrible, cosa que cambia cuando con una mano estoy sosteniendo un dispositivo y tengo que mover la vista del dispositivo al teclado pues aunque puedo escribir al tacto y con la mano izquierda están cubiertas esas letras, si hay mezcla con números, (10:6) se me complica o cuando son muchos caracteres.

Fijate en este caso, de un aparente exploit que había en una máquina y no podía copiarlo, entonces hice hexdump -C y captura de pantalla. Por supuesto no lo puedo encontrar, así que te muestro algo equivalente, los primeros bytes de /bin/ls:


Hexdump
Hexdump



Recordé que tengo un viejo teclado numérico QTronix, me parece que lo compré hace muchos mucho años en compucanje y algún Teensy 2, que viene a ser una variante de arduino, de hecho se programa con una variante de arduino ide llamada teensyduino y tiene la particularidad de funcionar como teclado USB con extrema sencillez. Hace un tiempo hice la conversión de un touchpad PS/2 a USB.

Habiendo puesto todos los ingredientes en el tazón, revolví y me dije, para qué voy a sufrir con los caracteres hexadecimales si puedo sufrir adaptando el teclado a USB y reprogramando unas teclas.

La reprogramación la hago en el Teensy antes de transmitir por USB, con el agregado de poder cambiar de modo, ya sea volver a las teclas nativas o cambiar de mayúscula a minúscula, apretando rápidas secuencias de una tecla de poco uso como es NumLock, la que controla que se envíen números o flechitas.


Primera etapa: preparativos


Determinar cuál es el modo común entre AP y X




El teclado tiene un switch que dice AP y X, calculo que viene a ser AT y XT, pues creo recordar que los teclados de las XT (8086) no eran compatibles con las AT (80286). Esta operación es muy fácil con un simple adaptador de DIN 5 180 grados a PS/2 lo tenemos:


Adaptador PS/2 a mini din a USB
Adaptador PS/2 a mini din a USB

Bueno, no tan simple, no tengo interfaz PS/2, no importa, si tengo un cajón llenísimo de todo tipo de basura adaptadora, igual que vos. Esto incluye un adaptador PS/2 a USB:

El cajón de adaptadores
El cajón de adaptadores

Te juro que empecé a ordenarlo para que se vea más lindo pero no, si uso mi tiempo en eso no lo uso en esto.



Listo, tal como esperaba es AP.


Medir consumo


Tendría que desarmar un poquito el teclado y medir. Luego agregarle el consumo del teensy, probablemente fabricando un cable USB donde puede poner en serie el tester o conseguir uno de estos:


Usb Tester
Usb Tester

No he hallado manera de que el mother te diga cuánto está consumiendo.

Mejor pensemos de otra manera:

Si el teclado con el adaptador PS/2 USB funciona, ¿qué tan distinto puede ser el consumo del Teensy? Listo, una preocupación menos.



Segunda etapa: implementar el software


Estoy seguro de tener una VM con teensyduino instalado, pero no recuerdo cuál. Si hubiera anotado en la descripción ese detalle podría encontrarlo, veamos...

Con este comando:

find $DIR1 $DIR2 -iname "*.vbox" | \
  while read CONF; do grep -ie teens -ie duino "$CONF";
done



Lo que hace el comando es buscar en las carpetas donde tengo VMs ($DIR1, $DIR2) archivos con extensión vbox y busca menciones a arduino o teensy.


No encontré nada, mala suerte. Ya instalaré una VM con eso. Uso mientras el de mi la máquina real, que no debería tener instaladas esas cosas.


Los requerimientos del programa son:

  • Debe convertir del protocolo del teclado PS/2 a USB Keyboard.
  • Debe reemplazar los keycodes determinados por [a-f] y tab.
  • Si se aprieta NumLock dos veces en rápida secuencia:
    • Debe cambiar ciclar entre [a-f] y [A-F]
  • Si se aprieta NumLock cuatro veces en rápida secuencia:
    • Debe cambiar ciclar entre el reemplazo y las funciones nativas.



+-----------+-----------+-----------+
|   print   |   scroll  |   pause   |
|   screen  |    lock   |           |
|    tab    |           |           |
+-----------+-----------+-----------+



+-----------+-----------+-----------+
|   insert  |    home   |  Page Up  |
|     A     |     B     |     C     |
+-----------+-----------+-----------+
|   delete  |    end    | Page Down |
|     D     |     E     |     F     |
+-----------+-----------+-----------+




El programa es básicamente el ejemplo de Teensy de adaptador de teclado PS/2 a USB, sólo que estoy mandando al Serial para diagnosticar.


include <PS2Keyboard.h>

const int DataPin = 5;
const int IRQpin =  3;

PS2Keyboard keyboard;
 
void setup() {
  delayMicroseconds(1000);
  Serial.begin(9600);
  keyboard.begin(DataPin, IRQpin);
  delay(2000);
  Serial.println("Keyboard Init");
}

void loop() {
 if (keyboard.available()) {
    char c = keyboard.read();

    if (c == PS2_ENTER) {
      Serial.println("[Enter]");
    } else if (c == PS2_TAB) {
      Serial.println("[Tab]");
    } else if (c == PS2_ESC) {
      Serial.println("[ESC]");
    } else if (c == PS2_PAGEDOWN) {
      Serial.
println("[PgDn]");
    } else if (c == PS2_PAGEUP) {
      Serial.
println("[PgUp]");
    } else if (c == PS2_LEFTARROW) {
      Serial.
println("[Left]");
    } else if (c == PS2_RIGHTARROW) {
      Serial.
println("[Right]");
    } else if (c == PS2_UPARROW) {
      Serial.
println("[Up]");
    } else if (c == PS2_DOWNARROW) {
      Serial.
println("[Down]");
    } else if (c == PS2_DELETE) {
      Serial.
println("[Del]");
    } else {
      Serial.println(c);
    }
  }
}


Y anda bastante bien, salvo que parece faltar una inicialización hacia el teclado, pues no prende la luz de KeyLock ni la detecta, asi como a varias otras teclas.


Prototipo, el teensy a la izquierda
Prototipo, el teensy a la izquierda


Tengo que analizar el protocolo, corre riesgo el proyecto, en pocos días regreso...


Debo además el cambio de función y mayúscula/minúscula y el armado físico.



Viewing all 264 articles
Browse latest View live